MQTT is a lightweight protocol, but in production the answers to “was the message delivered?”, “how does a newly connected subscriber learn the current value?” and “who notices when a device drops?” lie in three mechanisms: QoS, retain and Last Will.
QoS: delivery guarantee
| QoS | Guarantee | Cost | Typical use |
|---|---|---|---|
| 0 | At most once (fire and forget) | Lowest | Frequently updated telemetry; losing one sample does not matter |
| 1 | At least once (duplicates possible) | Medium | Important events, alarms; the receiver must tolerate duplicates |
| 2 | Exactly once | Highest (4-step handshake) | Rare commands where duplicates are harmful |
A practical rule: QoS 0 for telemetry, QoS 1 for events and alarms is enough; the overhead of QoS 2 is a luxury that is hard to justify in most field applications. With QoS 1 remember that the same message can arrive twice: design the receiver to be idempotent (for example by discarding duplicates using an event ID).
Also note that QoS applies to each hop between a client and the broker; even if the publisher sends with QoS 1, if the subscriber subscribed with QoS 0 delivery from the broker to the subscriber is QoS 0.
Retain: last known value
If a message is published with the retain flag, the broker stores the last message for that topic and immediately delivers it to every client that newly subscribes to it. A dashboard or application therefore sees the current state without waiting for the next change.
- Suitable: Slowly changing state (device online/offline, mode, configuration).
- Unsuitable: Events and commands. A retained “start” command is redelivered to every newly connected client.
- Clearing: To remove a retained message, publish an empty payload with the retain flag set to the same topic. Forgotten retained messages can make old data look “live”.
A retained value can be stale: even if the publisher dropped long ago, its last value keeps showing. Carry a timestamp with the data and combine state with Last Will, below.
Last Will: announcing a drop
When connecting, a client leaves a “will” message with the broker. If the client disconnects unexpectedly (network loss, power failure, timeout) the broker publishes it; if the client leaves cleanly (DISCONNECT) it is not published.
The classic pattern:
status topic: acme/istanbul/packaging/line-3/gateway/status
on connect : "online" (retain = true)
Last Will : "offline" (retain = true)
Every subscribing application then knows immediately and reliably whether the gateway is online. How quickly the broker notices a drop depends on the keep alive interval: too long and drops are detected late, too short and weak networks cause needless disconnects.
Session and expiry handling
- Persistent session: Even if a client drops, subscriptions and (QoS 1/2) pending messages can be kept at the broker and delivered on reconnect. Set queue and time limits to bound broker memory.
- Client ID: Use a unique, stable ID per client; if two clients connect with the same ID the broker disconnects the earlier one.
What MQTT 5.0 adds
MQTT 5.0 answers some industrial needs directly: reason codes, message and session expiry, user properties and shared subscriptions (load distribution across multiple consumers). Verify the 5.0 support and behavioral differences of the broker and client libraries you use.
Relationship to Sparkplug
Sparkplug B standardizes these mechanisms: the NDEATH message is a node’s MQTT Last Will, “birth” messages announce all of a node’s metrics and a retained STATE message is used for host application state. The same ideas are bound into a shared contract for device discovery and data freshness.
Checklist
- Telemetry → QoS 0; events/alarms → QoS 1 (+ idempotent receiver).
- State → retain; events and commands → retain off.
- Last Will + a retained “online” status message for every gateway/application.
- A timestamp and quality with the data.
- A cleanup procedure for old/retained topics.
- Keep-alive and session timings tested against real field network conditions.
It works best to consider these rules together with the topic structure in a Unified Namespace design; you can try the structure with our topic builder.