How to Choose MQTT QoS for SCADA Telemetry
Picking a quality of service level is one of the first real decisions in an MQTT telemetry design, and the wrong default costs you either lost data or wasted link. This guide is for the engineer who understands what QoS 0, 1, and 2 mean and now has to choose per message type across a fleet. It works through the decision by kind of message rather than reaching for one blanket level.
Choose MQTT QoS for Telemetry in one line: To choose MQTT QoS, match the level to the message's cost of loss and cost of duplication. Use QoS 0 for frequent live readings you will resend soon anyway, where a lost sample does not matter. Use QoS 1 for events, alarms, and commands you must not lose, accepting possible duplicates. Reserve QoS 2 for the rare message where a duplicate is genuinely unacceptable, because its extra handshake costs the most.
Start From What Each Level Guarantees
The choice only makes sense against what the levels promise, so anchor on that first. QoS 0 is at most once: fire and forget, no acknowledgement, a message may be lost and is never duplicated. QoS 1 is at least once: the message is retried until acknowledged, so it will arrive, but a retry can produce a duplicate. QoS 2 is exactly once: a four-part handshake guarantees the message arrives once and only once. The full mechanics are in the QoS levels reference; here we choose among them.
The two axes that matter for selection are the cost of losing a message and the cost of receiving it twice. Higher QoS reduces loss but raises overhead and, at QoS 1, introduces duplicates. So the decision is never QoS is better; it is which trade fits this particular message. A frequent reading and a once-a-day alarm sit at opposite ends of both axes and should not share a QoS just because it was convenient to set one value for the connection.
Match QoS to the Message Type
For frequent live process values, QoS 0 is usually right. If a tank level publishes every few seconds, losing one sample is harmless because another is moments away, and paying the acknowledgement overhead of QoS 1 on every reading wastes link and battery for no real benefit. The exception is when a reading is also the trigger for something, but for pure trending data that is superseded quickly, at most once is the efficient and correct choice, especially on a metered link.
For events, alarms, state changes, and commands, QoS 1 is the workhorse. These are messages where loss is unacceptable: a missed high-level alarm or a dropped setpoint command is a real problem, so you want the retry-until-acknowledged guarantee. The price is possible duplicates, which means the consumer must be built to tolerate them, an idempotent handler that processes the same alarm twice without double-counting. This duplicate handling is important enough to have its own treatment in QoS 1 duplicate delivery.
QoS 2 should be the exception, not a habit. Its exactly-once guarantee is genuinely valuable only where a duplicate would cause harm that idempotent design cannot absorb, and its four-way handshake is the heaviest of the three on the link and on broker state. For most SCADA, building consumers to tolerate the occasional duplicate and using QoS 1 is cheaper and more robust than reaching for QoS 2 everywhere. Save QoS 2 for the specific messages where duplicate suppression truly cannot be done downstream.
Account for the Link and Sparkplug
The link's character shifts the balance. On a flaky, high-latency cellular connection, QoS 1 retries can pile up if acknowledgements are slow, so pairing a sensible QoS with flow control matters, which is where receive maximum and flow control come in to bound the in-flight messages. A blanket high QoS on a bad link can make congestion worse, so the QoS choice and the link tuning are decided together, not in isolation.
If you run Sparkplug, some of the decision is guided for you. Sparkplug's design leans on the birth-death lifecycle and report by exception for correctness rather than on maximal QoS for every reading, and its critical lifecycle messages and commands are the ones that most want reliable delivery. So even within Sparkplug the pattern holds: reliable delivery for lifecycle and command messages, lighter treatment for the on-change data stream, chosen to match the cost of loss rather than applied uniformly.
Common Mistakes
The classic error is a single blanket QoS for the whole connection: QoS 0 everywhere, which quietly drops alarms, or QoS 2 everywhere, which needlessly loads the link and the broker. Almost as common is choosing QoS 1 for events but building a consumer that cannot tolerate the duplicates QoS 1 can produce, so the same alarm gets actioned twice. And choosing a high QoS on a poor link without any flow control, so retries compound congestion. Each of these comes from treating QoS as a global switch rather than a per-message decision, which is the habit this guide exists to break.
Frequently Asked Questions
Is QoS 2 always the safest choice?
No. QoS 2 gives exactly-once delivery, but its four-part handshake is the heaviest of the three levels on the link and on broker state, and that cost is wasted unless a duplicate would genuinely cause harm you cannot handle downstream. For most SCADA messages, using QoS 1 and building consumers to tolerate the occasional duplicate is cheaper and more robust. Reserve QoS 2 for the specific messages where duplicate suppression truly cannot be done in the consumer, not as a blanket safe default.
What QoS should I use for a frequently updated process value?
Usually QoS 0. A value that publishes every few seconds is superseded almost immediately, so losing one sample is harmless, and paying the acknowledgement overhead of QoS 1 on every reading wastes link bandwidth and battery for no real gain, which matters on a metered cellular plan. Reserve the higher levels for events, alarms, state changes, and commands, where loss actually matters. Choosing per message type rather than one blanket level is what keeps both reliability and efficiency where each is needed.
Sources and verification
This page references the protocol specifications published by the organizations below. Editions, product capabilities, and documentation change over time - confirm current requirements and specifications directly with the source.
- MQTT Version 5.0 (OASIS Standard) - OASIS (v5.0, 2019)
Merobix is not affiliated with, endorsed by, or sponsored by these organizations; their names are used only to identify the standards and products discussed.
Automation services
Need help turning this into a working system?
Merobix integrates SCADA, programs Allen-Bradley and Siemens PLCs, and designs and fabricates industrial control panels.
Meeting requests are reviewed before confirmation.