← Articles
MQTT/6 min read/ views

MQTT QoS and Retained Message Notes for SCADA

Practical notes for choosing MQTT QoS levels, retained messages, clean sessions, and duplicate handling in SCADA and industrial telemetry projects.

MQTTSCADANetworkingTroubleshootingTags

Why QoS and retain settings matter

MQTT is often introduced to a SCADA project as a lightweight publish/subscribe transport. The first test usually works quickly: a PLC gateway publishes a temperature, a broker receives it, and an HMI or historian subscribes.

The field problems start later:

  • A value reappears after a device has been removed.
  • A command is delivered twice after a reconnect.
  • A historian records stale startup values as if they were fresh readings.
  • A slow subscriber falls behind and the broker starts dropping or queuing messages.
  • Operators see good-looking values while the actual edge device is offline.

Most of these issues are not solved by "use QoS 1 everywhere." QoS, retained messages, session behavior, timestamps, and application-level state have to be designed together.

QoS is delivery behavior, not data quality

MQTT QoS describes how the broker and clients exchange a message. It does not prove that the value is current, accurate, or accepted by the PLC.

QoSMeaningSCADA use
0At most onceHigh-rate telemetry where the next value will arrive soon.
1At least onceImportant measurements and state changes where duplicates can be tolerated.
2Exactly once between MQTT endpointsRare in plant telemetry; higher overhead and not a substitute for command sequencing.

For most industrial telemetry, QoS 0 or QoS 1 is enough. QoS 2 sounds attractive, but it does not make an actuator command safe by itself. A motor start command still needs a command ID, permissive checks, feedback, timeout, and operator audit trail.

Treat QoS 1 duplicates as normal

QoS 1 can deliver the same message more than once. This is not a broker bug. It is part of the contract.

Design subscribers so duplicates are harmless:

  • Include a source timestamp in the payload.
  • Include a sequence number when order matters.
  • Make telemetry writes idempotent in the consuming system.
  • For commands, use a command ID and an acknowledgement topic.
  • Do not increment production counts just because the same MQTT message arrived again.

A common failure mode is a downtime counter or batch event table that assumes every incoming message is unique. After a network flap, the subscriber reconnects and processes a duplicate event. The report is now wrong even though the broker behaved correctly.

Use retained messages only where startup state is useful

A retained message is the last message the broker stores for a topic and sends immediately to new subscribers. This is useful for relatively static state, but dangerous when consumers cannot tell whether the value is fresh.

Good retained-message candidates:

  • Edge device birth information.
  • Model or firmware information.
  • Current mode or recipe name, if the payload includes timestamp and source state.
  • Last known equipment state when the UI clearly labels it as last known.

Poor retained-message candidates:

  • Momentary commands.
  • Alarm acknowledgement requests.
  • Fast analog samples.
  • One-shot batch events.
  • Values that look valid after the device is offline.

If retained telemetry is used, the HMI should display freshness. A retained pump speed from yesterday must not look the same as a live pump speed from the last second.

Separate telemetry, state, and commands

Do not mix all messages under one topic pattern with one QoS policy. Split topic classes by behavior.

Topic classExampleTypical settings
Telemetrysite/line1/press/pt101/pvQoS 0 or 1, usually not retained, source timestamp required.
Statesite/line1/filler/stateQoS 1, retained only if last-known state is useful and labelled.
Birth/deathsite/line1/gw01/statusQoS 1, retained birth plus Last Will for offline state.
Eventssite/line1/filler/eventsQoS 1, not retained, event ID required.
Commandssite/line1/filler/cmd/startQoS 1, not retained, command ID and response topic required.

This separation makes operations easier. When a stale retained command is found on a broker, it should be obvious that the topic policy is wrong.

Clean session and persistent session choices

Subscriber session behavior decides what happens while a client is offline. Persistent sessions can queue messages for later delivery. That sounds safe, but it can create a backlog that is no longer operationally useful.

For an HMI screen, old process samples are often useless. The screen needs the latest value and a clear quality state. For a historian event collector, queued events may be important, but the collector must process them with original source timestamps.

Field checks:

  • Know whether the client library uses clean session, clean start, or session expiry.
  • Limit queued messages for slow or disconnected subscribers.
  • Decide which subscribers are allowed to receive backlog.
  • Monitor broker queue depth and dropped message counters.
  • Test reconnect behavior by stopping the subscriber during live publishing.

A design that only works when every client is online is not a SCADA design; it is a lab demo.

Payload fields that prevent confusion

A practical payload does not need to be large, but it should carry enough context to survive reconnects and duplicates.

Useful fields:

  • value: the measurement, state, or event content.
  • sourceTimestamp: when the source system measured or produced it.
  • quality: good, uncertain, bad, simulated, forced, or device-specific quality.
  • sequence: monotonically increasing number per source when available.
  • source: gateway, PLC, device, or logical equipment identifier.

For command response payloads, include the command ID, accepted/rejected result, reason, and the equipment state after evaluation. Without this, troubleshooting turns into broker log archaeology.

Commissioning test sequence

Before calling the MQTT path ready for operations, run these tests with real broker settings.

  1. Start a subscriber after the publisher is already running and check which retained values arrive.
  2. Disconnect the publisher and confirm that the Last Will or offline state appears.
  3. Reconnect the publisher and verify that stale offline state is replaced.
  4. Stop a subscriber long enough to build backlog, then restart it and inspect ordering and timestamps.
  5. Force a duplicate QoS 1 message scenario by interrupting the network during publish acknowledgement.
  6. Confirm that commands are not retained and cannot execute again after a client restart.
  7. Check that the HMI distinguishes live, stale, bad, and last-known values.

Document the expected result for each topic class. The important part is not one perfect MQTT setting; it is that each topic behaves predictably during failure and recovery.

Practical rule of thumb

Use QoS 0 for disposable high-rate values, QoS 1 for important state and events, and retained messages only when a new subscriber truly needs the last known state. Then add timestamps, quality, sequence numbers, and command acknowledgements so the SCADA layer can make the right decision.

MQTT moves messages. SCADA still has to decide whether those messages are fresh, trustworthy, and safe to act on.