MQTT Keep Alive Explained: What It Is, How to Tune It, and Why Clients Disconnect
Your MQTT client connects, publishes a few readings, then goes quiet for five minutes. The broker marks it offline. When it tries to publish again, the connection is dead. This is the keep alive — the mechanism MQTT uses to tell the broker "I'm still here" when there's nothing to say.
This guide explains the MQTT keep alive from the wire up: the field in the CONNECT packet, the 1.5× timeout rule, PINGREQ and PINGRESP, how Last Will interacts with it, and how to pick the right interval for battery-powered sensors, industrial controllers, and laptops on flaky Wi-Fi.
What the Keep Alive Actually Is
The keep alive is a single 16-bit number in the CONNECT packet — the packet every client sends first when it connects. It's measured in seconds, and it tells the broker the maximum time it can wait with zero traffic before the client is presumed dead.
CONNECT packet (simplified)
┌──────────────┬───────────────┬───────────────┐
│ Protocol │ Flags │ Keep Alive │
│ Name "MQTT" │ (clean start │ (2 bytes, │
│ │ etc.) │ seconds) │
└──────────────┴───────────────┴───────────────┘
Example: 00 3C = 60 seconds keep alive
A keep alive of 60 means: "if you hear nothing from me for 60 seconds, start a second timer — and if another 30 seconds pass (1.5× total) with still nothing, you can assume I'm gone."
The critical detail: the broker counts from the last packet of any kind — a publish, a subscribe, a PINGREQ, anything. Traffic resets the timer.
The 1.5× Rule and Why It Exists
MQTT doesn't disconnect at exactly the keep alive value. It disconnects at 1.5× the keep alive:
Keep alive = 60 s
Broker's patience = 60 × 1.5 = 90 s
t = 0 Last packet received
t = 60 s Keep alive elapses — broker begins waiting for the next packet
t = 90 s Still nothing → broker closes the connection
Why the extra 50%? Because it's the client's job to send something before the keep alive elapses — and the broker is deliberately lenient about it. TCP itself takes time to signal a dead peer, and a client that's simply slow is different from a client that's gone. The 1.5× window separates "your client is a few seconds late" from "your client is never coming back."
Practical takeaway: a client should send a PINGREQ when roughly 50–75% of the keep alive has elapsed with no other traffic — not at 100%. That guarantees the broker always sees a packet inside its window.
PINGREQ and PINGRESP: The Heartbeat
When a client has nothing to publish and the keep alive is approaching, it sends a 2-byte PINGREQ packet. The broker answers with a 2-byte PINGRESP. That exchange resets the timer on both sides.
Client → Broker: PINGREQ (0xC0 0x00)
Broker → Client: PINGRESP (0xD0 0x00)
Both packets are 2 bytes. No payload.
Three failure modes to know:
- Broker doesn't reply to PINGREQ — the connection is stale; the client should close it and reconnect.
- Client never pings — the broker's 1.5× timer expires and the broker closes the connection.
- Network drops silently — no FIN, no RST, just silence (common on cellular). Keep alive is the only thing that detects this at the MQTT layer.
The last one is the real reason keep alive exists. TCP keepalive (off by default on most stacks) can take 2 hours to notice a dead peer. MQTT's keep alive gives you application-level detection in seconds or minutes.
Keep Alive + Last Will = Reliable Offline Detection
Keep alive and Last Will work together. When the broker's 1.5× timer expires, it:
- Closes the TCP connection,
- Fires the client's Last Will message if one was set,
- Marks the session's will as published (MQTT 5) or removes the session.
This is the standard "device went offline" signal in industrial telemetry: the will message lands on a status topic, and the monitoring dashboard flips the device to OFFLINE. Without a keep alive, a dead sensor would look online forever.
Important nuance: a client that disconnects gracefully (sends DISCONNECT) does not trigger the will — the client is expected to be back. The will only fires on an abnormal death, which is exactly what the keep alive timer detects.
What Happens When the Keep Alive Is 0
A keep alive of 0 means "no keep alive." The broker never times the client out, and the client never pings. The connection lives until the TCP layer or the broker's own limits (if any) kill it.
This is a legitimate choice for:
- Long-lived gateways on stable networks that publish continuously anyway,
- Local, trusted MQTT where the broker and client are on the same LAN,
- Fixed-line industrial links where TCP timeouts are already acceptable.
It's a bad choice for cellular IoT and anything battery-powered, where silent disconnects are the norm and a dead device should be detectable.
Choosing the Right Keep Alive Interval
There's no universal value — the right one depends on how often your device talks and how fast you need to know it died.
| Scenario | Suggested Keep Alive | Why |
|---|---|---|
| Battery sensor publishing every 5 min | 30–60 s | Pings between publishes; broker detects death in under 2 min |
| Industrial PLC / gateway | 15–60 s | Fast detection of plant-floor link drops |
| Phone / laptop app | 60–120 s | Balances battery (cellular radios hate frequent pings) with reasonable detection |
| WebSocket MQTT | 30–60 s | Browser tabs get suspended; shorter intervals keep brokers honest |
Two rules of thumb:
- Never let the keep alive exceed your publish gap unless you want the broker to think the device died between publishes. If you publish every 10 minutes, use a keep alive of 60 seconds and let pings cover the quiet time.
- Don't set it tiny on battery power. A 10-second keep alive on cellular means a PINGREQ every ~7 seconds — the radio spends more time alive than asleep.
Common bug: devices that publish rarely (hourly) with a keep alive of 60 seconds usually work — because most clients send PINGREQ automatically. But clients with broken ping implementations silently get disconnected by the broker's 1.5× timer. If you see devices flapping on and off, check the client's ping behavior first.
How to Debug Keep Alive Problems
When clients drop unexpectedly, the fastest way to see what's happening is to watch the packets at the broker:
- Enable broker protocol logging — mosquitto with
-v, or the equivalent in your broker, prints every CONNECT, PINGREQ, PINGRESP, and disconnect with a reason. - Look for the disconnect reason — MQTT 5 brokers report why a connection closed (keep alive timeout is a distinct reason code).
- Time the gaps — if packets stop arriving well before the keep alive, the problem is the network path, not the setting.
- Test with a GUI client — an MQTT explorer that shows connection state and protocol activity makes the ping/pong rhythm visible instead of guessable.
A pattern that looks like a keep-alive bug but usually isn't: clients disconnecting at exactly the same time every day. That's almost always a broker-side idle timeout, a firewall rule, or a NAT session timeout — not MQTT's keep alive. Corporate firewalls and carrier NAT commonly drop idle TCP sessions at 5 or 30 minutes regardless of what MQTT wants.
The Bottom Line
MQTT keep alive is a CONNECT-packet field, in seconds, that sets how long the broker will wait with zero traffic before declaring the client dead — enforced at 1.5× the value. Clients stay alive by sending 2-byte PINGREQ packets, answered by PINGRESP, whenever the keep alive approaches with nothing else to send.
Choose the interval based on your publish cadence and how quickly a dead device must be noticed: 30–60 seconds suits most industrial and IoT deployments, 0 is acceptable only on stable local links, and battery devices should favor shorter ping duty cycles rather than aggressive keep alives.
When devices flap on and off, the cause is usually silent network drops that only the keep alive can detect — which is exactly the problem it was designed to solve.
Watch MQTT Connections Live
MQTT Explorer for macOS shows connection state, protocol traffic, and retained data in real time. Connect to any broker and see keep alives working — without a terminal.
Explore MQTT Explorer →