Pour supprimer un message retenu MQTT, vous n'avez besoin d'aucun outil d'administration du broker : il suffit de publier un payload de longueur nulle avec le flag retain activé sur le même topic, et le broker abandonne la valeur stockée. Ce guide présente cette technique depuis la ligne de commande, Python, JavaScript et un client dans le navigateur, et explique comment repérer et effacer en masse, en toute sécurité, les topics retenus obsolètes.
Pourquoi les messages retenus restent bloqués
Un retained message est le dernier message qu'un broker conserve pour un topic, afin que tout nouveau subscriber reçoive immédiatement la valeur actuelle. C'est exactement ce que l'on veut pour le statut d'un appareil, un document de configuration ou la dernière mesure d'un capteur. Si la fonctionnalité est nouvelle pour vous, le guide des messages retenus MQTT en détaille le fonctionnement.
Les ennuis commencent quand la valeur stockée cesse d'être vraie. Situations typiques :
- Un appareil a été mis hors service, mais son dernier statut
onlinecontinue d'apparaître dans les tableaux de bord. - Une publication de test avec le flag retain, faite pendant le développement, pollue désormais une arborescence de topics de production.
- Un topic de configuration a été renommé, et l'ancien envoie toujours des paramètres périmés aux nouveaux clients.
- Un bug de firmware a publié du JSON mal formé avec retain, et chaque subscriber qui se reconnecte plante dessus.
Comme le broker rejoue la valeur retenue à chaque nouvel abonnement, le problème ne disparaît jamais de lui-même. Vous devez remplacer la valeur stockée ou la supprimer.
Comment supprimer un message retenu MQTT
La spécification MQTT définit la règle en une phrase : un paquet PUBLISH avec le flag RETAIN à 1 et un payload de longueur nulle supprime tout retained message pour ce topic, et le broker n'en stocke pas de nouveau. Le message vide est également transmis aux subscribers actuels : vos consommateurs doivent donc tolérer un payload vide au lieu d'essayer de l'analyser comme du JSON.
Quelques détails comptent en pratique :
- Le topic doit correspondre exactement. Les retained messages sont stockés par nom de topic. Publier un message retenu vide sur
sensors/#n'a aucun effet, car les wildcards ne sont pas autorisés dans les noms de topics sur lesquels on publie. - Le payload doit être réellement vide. Un simple espace, un objet JSON vide
{}ou la chaînenullsont de vrais payloads et seront retenus comme nouvelle valeur. - La QoS importe peu. La QoS 0 convient pour un nettoyage, mais la QoS 1 vous donne un accusé de réception confirmant que le broker l'a reçu.
- Vous devez avoir le droit de publier sur ce topic. Si vos identifiants ne le permettent pas, la suppression est rejetée ou ignorée silencieusement selon le broker et la version du protocole.
Effacer des messages retenus avec mosquitto_pub
Les outils en ligne de commande Mosquitto sont le moyen le plus rapide d'effacer un topic unique. Le flag -r active retain et -n envoie un message nul (de longueur zéro) :
# Voir ce qui est actuellement retenu sur le topic
mosquitto_sub -h broker.connectmq.com -p 1883 -i inspect-7f3a \
-t "connectmq/demo/7f3a/device42/status" -v -C 1 -W 5
# Supprimer le message retenu
mosquitto_pub -h broker.connectmq.com -p 1883 -i cleanup-7f3a \
-t "connectmq/demo/7f3a/device42/status" -r -n
# Vérifier : la commande doit maintenant expirer sans rien afficher
mosquitto_sub -h broker.connectmq.com -p 1883 -i verify-7f3a \
-t "connectmq/demo/7f3a/device42/status" -v -C 1 -W 5
La combinaison -C 1 -W 5 indique à mosquitto_sub de s'arrêter après un message ou cinq secondes, ce qui en fait une sonde rapide pour savoir si quelque chose est retenu. Les exemples utilisent le serveur MQTT public gratuit, réservé aux tests, avec un préfixe unique ; remplacez 7f3a par votre propre identifiant aléatoire.
Sur un broker privé, ajoutez les identifiants et 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
Nettoyage en masse avec --remove-retained
mosquitto_sub dispose d'une option pratique pour des sous-arbres entiers. Avec --remove-retained, chaque retained message reçu est effacé en republiant un message retenu vide sur ce topic. Combinez-la avec --retained-only pour ne toucher que les valeurs retenues et ignorer le trafic en direct :
mosquitto_sub -h broker.connectmq.com -p 1883 -i purge-7f3a \
-t "connectmq/demo/7f3a/#" --retained-only --remove-retained -v -W 5
Lancez d'abord la commande d'inspection, lisez attentivement la liste, puis purgez. Un wildcard comme # sur une arborescence partagée peut supprimer bien plus que prévu.
Supprimer un message retenu avec Python
Lorsque le nettoyage fait partie d'un script de mise hors service, Python avec paho-mqtt 2.x est pratique. Passer payload=None produit un payload de longueur nulle :
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()
Repérer et effacer tout un sous-arbre
Cette version s'abonne avec un wildcard, collecte pendant un court intervalle chaque topic qui délivre un retained message, puis les efface un par un. Elle limite le rythme de publication, ce qui compte sur le serveur MQTT public gratuit où chaque client est limité à 10 messages par seconde.
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) # collecter les messages retenus
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) # rester sous la limite de débit par client
client.loop_stop()
client.disconnect()
Notez la vérification msg.retain. Les brokers positionnent le flag retain sur les messages délivrés en raison d'un nouvel abonnement : les messages en direct qui arrivent pendant l'intervalle ne sont donc pas confondus avec des valeurs stockées.
Supprimer un message retenu depuis JavaScript ou le navigateur
Avec MQTT.js, la même règle s'applique : une chaîne vide ou un buffer vide avec 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();
}
);
});
Si vous préférez ne pas écrire de code du tout, le client MQTT intégré au navigateur du portail ConnectMQ fonctionne aussi : connectez-vous à votre broker, saisissez le topic exact, laissez le champ payload vide, activez retain et publiez. L'explorateur de topics en direct permet de voir quels topics contiennent encore une valeur avant et après le nettoyage.
Dépanner un message retenu qui refuse de disparaître
| Symptôme | Cause probable | Solution |
|---|---|---|
| L'ancienne valeur réapparaît quelques secondes plus tard | Un appareil ou un service la publie encore avec retain | Trouvez le publisher, corrigez son flag retain, puis effacez à nouveau |
| Rien ne change après la publication vide | Topic différent (casse, slash final, niveau en trop) | Copiez le topic exact depuis la sortie d'un abonnement -v |
| Les subscribers plantent après le nettoyage | Les consommateurs analysent le payload vide | Ignorez les messages de longueur nulle dans le gestionnaire de messages |
| La valeur est remplacée, pas supprimée | Le payload était un espace, {} ou null |
Utilisez -n ou payload=None, pas une chaîne de substitution |
| Le nettoyage fonctionne en test, pas en production | Les identifiants n'ont pas le droit de publier sur ce topic | Utilisez le compte propriétaire de l'arborescence de topics |
La première ligne est de loin la plus fréquente. Une valeur retenue qui « revient » est presque toujours republiée par quelque chose : souvent un script de pont, un flux Node-RED ou un appareil qui publie son statut avec retain à chaque reconnexion.
Éviter dès le départ les données retenues obsolètes
Supprimer des messages retenus est une tâche de nettoyage ; bien les concevoir réduit la fréquence à laquelle vous devez le faire.
- Utilisez l'expiration des messages MQTT 5. Définissez un Message Expiry Interval sur les publications retenues pour que le broker les supprime après un certain délai. Le guide du message expiry interval présente des valeurs raisonnables.
- Associez le statut au Last Will. Un statut
onlineretenu doit être associé à un message Last Willofflineretenu, pour que la valeur stockée reste exacte quand un appareil décroche. - Limitez le nombre de topics retenus. Retenez l'état, pas les flux. La télémétrie à haute fréquence a rarement besoin de retain, et moins de topics retenus signifie moins de nettoyage.
- Ne traitez pas les messages retenus comme une base de données. Ils conservent la dernière valeur par commodité, pas un historique durable. Stockez tout ce que vous devez garder dans une vraie base de données alimentée par un subscriber.
- Documentez les topics retenus. Une courte liste dans vos conventions de nommage des topics évite les surprises lorsque quelqu'un ajoute un abonnement avec wildcard.
Le comportement complet du flag retain est spécifié dans le standard OASIS MQTT 5.0, et le tutoriel MQTT, plus général, replace les messages retenus dans leur contexte avec la QoS, les sessions et les wills.
Gérer les topics retenus sur ConnectMQ
ConnectMQ prend en charge les messages retenus en MQTT 3.1.1 comme en 5.0 : toutes les techniques ci-dessus fonctionnent sans modification. Si vous dépassez le stade des expérimentations, un broker MQTT managé vous fournit des identifiants privés, TLS sur le port 8883 et un portail avec un client intégré au navigateur et un explorateur de topics en direct pour ce type de maintenance. Vous pouvez aussi en savoir plus sur l'exploitation d'un broker MQTT dans le cloud sans gérer vous-même de serveurs.
Créez un broker Serverless gratuit sur app.connectmq.com, sans carte bancaire, et vous disposerez d'un nom d'utilisateur, d'un mot de passe et d'un client ID en quelques minutes.
Questions fréquentes
Comment supprimer un message retenu en MQTT ?
Publiez un message avec un payload de longueur nulle et le flag retain activé sur exactement le même topic. Avec Mosquitto, c'est mosquitto_pub -t <topic> -r -n, et le broker cesse de stocker une valeur retenue pour ce topic.
Puis-je supprimer tous les messages retenus avec un wildcard ?
Pas avec une seule publication, car les wildcards ne sont pas autorisés dans les noms de topics. Abonnez-vous avec un filtre wildcard pour découvrir les topics retenus, puis effacez-les un par un, ou utilisez mosquitto_sub --retained-only --remove-retained.
L'envoi d'un objet JSON vide supprime-t-il le message retenu ?
Non. {} est un payload de deux octets, que le broker retient comme nouvelle valeur. Seul un payload réellement vide supprime le message retenu.
Les subscribers reçoivent-ils le message vide ?
Oui, les subscribers actuels reçoivent le message de longueur nulle comme n'importe quelle autre publication. Assurez-vous que vos consommateurs ignorent les payloads vides au lieu d'échouer à les analyser.



