An MQTT retained message is useful for reporting the last known state, but it can be dangerous when treated as a fresh actuator command. A newly connected subscriber receives the broker’s retained value immediately, even if the publisher that created it disappeared hours earlier. Keep durable state and one-shot commands on different topics, and give time-sensitive MQTT 5 messages an expiry interval.
The failure begins at reconnection
Consider a workshop controller subscribed to lab/extractor/cmd. An operator once published ON with the retain flag. The broker stored that payload. After maintenance, the controller reconnects and subscribes again; MQTT delivers the retained ON as the latest value on the topic. If firmware interprets every arrival as a new command, the extractor starts without a new operator action.
This behavior is not a broker defect. The MQTT 5 specification says a retained PUBLISH replaces the retained message for that topic and is sent to future matching subscribers. Retention answers “what was the last published value?” It does not prove that the value is still timely or that its original issuer is still authorized to act.

Separate state topics from command topics
A robust topic contract gives state and commands different semantics. A device can publish retained state such as lab/extractor/state = ON after it has actually changed output. A controller can publish a non-retained request on lab/extractor/cmd. The actuator then reports the resulting state independently.
That separation makes a dashboard useful after reconnecting without replaying an old instruction. It also prevents acknowledgements, telemetry and commands from collapsing into one ambiguous “status” topic. Access-control rules can be narrower: operator clients may write the command topic, while the device alone writes its state topic.
For requests that must survive a short disconnect, include an identifier and creation time in the payload, and make handling idempotent. A receiver should reject an already-processed command ID and compare the timestamp or expiry policy before changing an output. Broker retention alone cannot supply that application-level decision.
Use MQTT 5 expiry as a bounded lifetime
MQTT 5 adds the Message Expiry Interval property, expressed as a four-byte unsigned integer in seconds. The broker decreases the remaining interval while a message is stored. Once the interval reaches zero, the message is no longer published. That gives a time-sensitive retained value a defined lifetime instead of leaving it indefinitely.
With Mosquitto’s command-line client, a 30-second retained publication can be expressed as:
mosquitto_pub -V mqttv5 -t lab/extractor/cmd -m ON -r -D publish message-expiry-interval 30
This bounds broker storage, but it does not replace receiver checks. Clock-free devices still need command IDs or a local state machine, and MQTT 3.1.1 clients do not have the MQTT 5 expiry property.

Clear legacy retained commands deliberately
The MQTT standard clears a retained value when the broker receives a retained PUBLISH with a zero-byte payload for the same topic. Mosquitto provides the direct form:
mosquitto_pub -t lab/extractor/cmd -r -n
Clearing is a migration step, not the full repair. If publishers keep retaining commands, the stale state returns. Update publisher defaults, topic documentation and broker permissions together. Mosquitto’s subscriber also has --remove-retained --retained-only for administrative cleanup across a subscribed tree; use that only with a reviewed topic filter because it removes retained records broadly.
A command contract that fails closed
For physical outputs, define four rules: command topics are non-retained by default; retained values describe observed state; time-limited requests carry MQTT 5 expiry; and the receiver validates identity, authorization and freshness before acting. On startup, the device should move to its documented safe state or preserve its local state according to the application—not infer safety from whichever network message arrives first.
Smart-home radio reliability is a separate layer. TVG’s Matter-over-Thread baseline map explains how to record the physical network before blaming application logic.


My system failed when I used that specific configuration because the old data persisted too long.