MQTT Fundamentals

How to Delete a Retained Message in MQTT (CLI, Python and Web Client)

A stale retained message keeps greeting every new subscriber with old data. Here is how to delete a retained message in MQTT with an empty retained publish, from the command line, Python, JavaScript and a browser client.

Illustration of a broker topic tree where a stale value is cleared to show how to delete retained message mqtt entries
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

To delete retained message MQTT entries you do not need a broker admin tool: you publish a zero-length payload with the retain flag set to the same topic, and the broker drops the stored value. This guide shows that technique from the command line, Python, JavaScript and a browser client, plus how to find and bulk-clear stale retained topics safely.

Why Retained Messages Get Stuck

A retained message is the last message a broker stores for a topic so that any new subscriber immediately receives the current value. That is exactly what you want for a device status, a configuration document or the latest sensor reading. If you are new to the feature, the guide to MQTT retained messages explains the mechanics in detail.

The trouble starts when the stored value stops being true. Typical situations:

  • A device was decommissioned, but its last online status keeps appearing in dashboards.
  • A test publish with the retain flag set during development now pollutes a production topic tree.
  • A configuration topic was renamed, and the old one still delivers outdated settings to new clients.
  • A firmware bug published malformed JSON with retain, and every reconnecting subscriber crashes on it.

Because the broker replays the retained value on every new subscription, the problem never goes away by itself. You have to replace the stored value or remove it.

How to Delete a Retained Message in MQTT

The MQTT specification defines the rule in one sentence: a PUBLISH packet with the RETAIN flag set to 1 and a zero-length payload removes any retained message for that topic, and the broker does not store a new one. The empty message is also forwarded to current subscribers, so your consumers should tolerate an empty payload instead of trying to parse it as JSON.

A few details matter in practice:

  1. The topic must match exactly. Retained messages are stored per topic name. Publishing an empty retained message to sensors/# does nothing, because wildcards are not allowed in topic names you publish to.
  2. The payload must be truly empty. A single space, an empty JSON object {} or the string null are all real payloads and will be retained as the new value.
  3. QoS does not matter much. QoS 0 is fine for a cleanup, but QoS 1 gives you an acknowledgement that the broker received it.
  4. You need publish permission on that topic. If your credentials cannot publish there, the deletion is rejected or silently dropped depending on the broker and protocol version.

Clear Retained Messages with mosquitto_pub

The Mosquitto command-line tools are the fastest way to clear a single topic. The -r flag sets retain and -n sends a null (zero-length) message:

# Inspect what is currently retained on the topic
mosquitto_sub -h broker.connectmq.com -p 1883 -i inspect-7f3a \
  -t "connectmq/demo/7f3a/device42/status" -v -C 1 -W 5

# Delete the retained message
mosquitto_pub -h broker.connectmq.com -p 1883 -i cleanup-7f3a \
  -t "connectmq/demo/7f3a/device42/status" -r -n

# Confirm: this should now time out without printing anything
mosquitto_sub -h broker.connectmq.com -p 1883 -i verify-7f3a \
  -t "connectmq/demo/7f3a/device42/status" -v -C 1 -W 5

The -C 1 -W 5 combination tells mosquitto_sub to exit after one message or five seconds, which turns it into a quick "is anything retained here?" probe. The examples use the public MQTT test broker with a unique prefix; replace 7f3a with your own random ID.

On a private broker, add credentials and TLS:

mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID \
  -t "plant1/line2/press/status" -r -n -q 1

Bulk Cleanup with --remove-retained

mosquitto_sub has a helpful option for whole subtrees. With --remove-retained, every retained message it receives is cleared by publishing an empty retained message back to that topic. Combine it with --retained-only so it only touches retained values and ignores live traffic:

mosquitto_sub -h broker.connectmq.com -p 1883 -i purge-7f3a \
  -t "connectmq/demo/7f3a/#" --retained-only --remove-retained -v -W 5

Run the inspection command first, read the list carefully, then purge. A wildcard such as # on a shared tree can delete far more than you intended.

Delete a Retained Message with Python

When cleanup is part of a decommissioning script, Python with paho-mqtt 2.x is convenient. Passing payload=None produces a zero-length payload:

import time
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
TOPIC = "connectmq/demo/7f3a/device42/status"

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    info = client.publish(TOPIC, payload=None, qos=1, retain=True)
    info.wait_for_publish(timeout=5)
    print("Retained message cleared on", TOPIC)
    client.disconnect()

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="cleanup-py-7f3a")
client.on_connect = on_connect
client.connect(BROKER, 1883, keepalive=30)
client.loop_forever()

Find and Clear a Whole Subtree

This version subscribes with a wildcard, collects every topic that delivers a retained message during a short window, and then clears them one by one. It throttles publishing, which matters on the public broker where each client is limited to 10 messages per second.

import time
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
FILTER = "connectmq/demo/7f3a/#"
found = set()

def on_message(client, userdata, msg):
    if msg.retain and msg.payload:
        found.add(msg.topic)

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(FILTER, qos=1)

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="purge-py-7f3a")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
time.sleep(3)  # collect retained messages

print(f"Found {len(found)} retained topics")
for topic in sorted(found):
    print("Clearing", topic)
    client.publish(topic, payload=None, qos=1, retain=True).wait_for_publish(5)
    time.sleep(0.15)  # stay under the per-client rate limit

client.loop_stop()
client.disconnect()

Note the msg.retain check. Brokers set the retain flag on messages delivered because of a new subscription, so live messages that happen to arrive during the window are not mistaken for stored values.

Delete a Retained Message from JavaScript or the Browser

With MQTT.js the same rule applies: an empty string or empty buffer with retain: true.

const mqtt = require("mqtt");

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "cleanup-js-7f3a",
  protocolVersion: 5,
});

client.on("connect", () => {
  client.publish(
    "connectmq/demo/7f3a/device42/status",
    "",
    { qos: 1, retain: true },
    (err) => {
      console.log(err ? `Failed: ${err.message}` : "Retained message cleared");
      client.end();
    }
  );
});

If you prefer not to write code at all, the in-browser MQTT client in the ConnectMQ portal works too: connect to your broker, enter the exact topic, leave the payload field empty, enable retain and publish. The live topic explorer is a good way to see which topics still hold a value before and after the cleanup.

Troubleshooting a Retained Message That Will Not Go Away

Symptom Likely cause Fix
Old value reappears seconds later A device or service is still publishing it with retain Find the publisher, fix its retain flag, then clear again
Nothing changes after the empty publish Topic mismatch (case, trailing slash, extra level) Copy the exact topic from a -v subscription output
Subscribers crash after cleanup Consumers parse the empty payload Skip zero-length messages in the message handler
Value is replaced, not removed Payload was a space, {} or null Use -n or payload=None, not a placeholder string
Cleanup works on test, not production Credentials lack publish rights on that topic Use the account that owns the topic tree

The first row is by far the most common. A retained value that "comes back" is almost always being republished by something, often a bridge script, a Node-RED flow or a device that publishes its status with retain on every reconnect.

Avoid Stale Retained Data in the First Place

Deleting retained messages is a cleanup task; designing them well reduces how often you need it.

  • Use MQTT 5 message expiry. Set a Message Expiry Interval on retained publishes so the broker discards them after a period. The message expiry interval guide covers sensible values.
  • Pair status with Last Will. A retained online status should be paired with a retained offline Last Will message, so the stored value stays accurate when a device drops.
  • Keep retained topics narrow. Retain state, not streams. High-frequency telemetry rarely needs retain, and fewer retained topics means less to clean.
  • Do not treat retained messages as a database. They hold the latest value for convenience, not durable history. Store anything you need to keep in a real database fed by a subscriber.
  • Document which topics are retained. A short list in your topic naming conventions prevents surprises when someone adds a wildcard subscription.

The full behaviour of the retain flag is specified in the OASIS MQTT 5.0 standard, and the broader MQTT tutorial puts retained messages in context with QoS, sessions and wills.

Manage Retained Topics on ConnectMQ

ConnectMQ supports retained messages on both MQTT 3.1.1 and 5.0, so every technique above works unchanged. If you are moving beyond experiments, a managed MQTT broker gives you private credentials, TLS on port 8883 and a portal with an in-browser client and live topic explorer for this kind of housekeeping. You can read more about running an MQTT broker in the cloud without operating servers yourself.

Create a free Serverless broker at app.connectmq.com, no credit card required, and you will have a username, password and client ID in a couple of minutes.

Frequently Asked Questions

How do I delete a retained message in MQTT?

Publish a message with a zero-length payload and the retain flag set to the exact same topic. With Mosquitto that is mosquitto_pub -t <topic> -r -n, and the broker stops storing a retained value for that topic.

Can I delete all retained messages with a wildcard?

Not with a single publish, because wildcards are not allowed in topic names. Subscribe with a wildcard filter to discover retained topics, then clear each one, or use mosquitto_sub --retained-only --remove-retained.

Does sending an empty JSON object delete the retained message?

No. {} is a two-byte payload, so the broker retains it as the new value. Only a truly empty payload removes the retained message.

Do subscribers receive the empty message?

Yes, current subscribers receive the zero-length message like any other publish. Make sure your consumers ignore empty payloads instead of failing to parse them.

Related articles

Why Your MQTT Client Keeps Disconnecting (and How to Fix It)

Reconnect loops are one of the most common MQTT problems. Learn the five usual causes, from duplicate client IDs to keep alive timeouts and oversized packets, and follow a diagnosis flow that pinpoints yours.

8 min read

Who Invented MQTT? The History from Oil Pipelines to IoT

MQTT was invented in 1999 by Andy Stanford-Clark of IBM and Arlen Nipper of Arcom to monitor oil pipelines over satellite. Follow its path to open source, OASIS, ISO and today's managed cloud brokers.

7 min read

MQTT Maximum Message Size: Limits and Large Payload Strategies

MQTT can technically carry a 256 MB packet, but brokers, client libraries and devices impose far lower limits. Learn where the real limits are, what happens when you exceed them, and how to send large payloads.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.