Fondamentaux MQTT

Retained messages MQTT : fonctionnement et cas d'usage

Le flag retain permet à un broker MQTT de transmettre immédiatement à chaque nouvel abonné la dernière valeur connue d'un topic. Découvrez son fonctionnement, ses points forts et les bugs de données périmées qu'il peut provoquer.

Broker stockant la dernière valeur de chaque topic pour illustrer les retained messages MQTT destinés aux nouveaux abonnés
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Les retained messages MQTT résolvent un problème simple mais agaçant : un client qui s'abonne à un topic doit attendre la prochaine publication avant de savoir quoi que ce soit. Avec le flag retain, le broker conserve le dernier message de ce topic et le livre immédiatement à chaque nouvel abonné. Dans ce guide, vous verrez précisément comment se comportent les retained messages, vous les testerez sur le serveur MQTT public gratuit de ConnectMQ et vous apprendrez quand les utiliser et quand les éviter.

Ce que sont les retained messages MQTT

Chaque paquet PUBLISH MQTT porte un flag retain d'un bit. Lorsqu'un client publie avec retain à true, le broker fait deux choses : il transmet le message aux abonnés actuels comme d'habitude, et il en stocke une copie comme retained message de ce topic précis. Chaque topic conserve au plus un retained message : une nouvelle publication retained remplace donc l'ancienne.

Lorsqu'un client s'abonne plus tard à un filtre correspondant à ce topic, le broker envoie le message stocké juste après le SUBACK. L'abonné voit le flag retain activé sur cette livraison, ce qui lui indique « ceci est la dernière valeur connue, pas un événement récent ». Les abonnements à jokers fonctionnent aussi : s'abonner à factory/+/status renvoie d'un coup le retained message de chaque topic correspondant.

Quelques règles faciles à manquer :

  • La rétention est par topic, pas par client. N'importe quel client peut écraser la valeur retained.
  • Publier avec retain et un payload vide (zéro octet) supprime le retained message.
  • Les messages transmis aux abonnés déjà connectés arrivent normalement avec le flag retain à zéro en MQTT 3.1.1. MQTT 5 ajoute l'option d'abonnement « retain as published » pour le conserver.
  • La QoS de la livraison retained est la plus faible entre la QoS du message stocké et celle de l'abonnement.

Si vous avez besoin d'un rappel sur la façon dont un broker achemine les messages en général, lisez d'abord ce que fait un broker MQTT.

Comment le flag retain change la livraison

La façon la plus simple de comprendre la différence consiste à comparer la même publication avec et sans retain.

Scénario Retain false Retain true
Abonné en ligne au moment de la publication Reçoit le message Reçoit le message
Abonné se connectant 5 minutes plus tard Ne reçoit rien jusqu'à la prochaine publication Reçoit immédiatement la dernière valeur
Seconde publication sur le même topic Livrée, rien n'est stocké Livrée, remplace la valeur stockée
Publication d'un payload vide Livre un message vide Supprime la valeur stockée
Abonnement à joker Uniquement les messages futurs Dernière valeur de chaque topic correspondant

C'est pourquoi on décrit souvent les retained messages comme la « dernière valeur valide connue ». Ils transforment un flux d'événements en quelque chose que l'on peut interroger en s'abonnant.

Tester les retained messages sur le serveur MQTT public gratuit

Vous pouvez le vérifier en moins d'une minute avec les outils en ligne de commande Mosquitto sur le serveur MQTT public gratuit broker.connectmq.com. Il accepte les connexions anonymes avec n'importe quel client ID non vide. Utilisez un préfixe de topic unique, car tout ce qui se trouve dans l'espace public est lisible par tous : ce serveur sert aux tests et aux prototypes, pas aux données de production.

Publiez d'abord une valeur retained, puis déconnectez-vous :

mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-pub-r7k2 \
  -t connectmq/demo/r7k2/thermostat/setpoint \
  -m '{"setpoint":21.5,"unit":"C"}' -q 1 -r

Abonnez-vous maintenant depuis un autre terminal. Bien que personne ne publie, la valeur arrive instantanément. Le flag -v affiche le topic et -F permet d'afficher explicitement le flag retain :

mosquitto_sub -h broker.connectmq.com -p 1883 -i demo-sub-r7k2 \
  -t 'connectmq/demo/r7k2/#' -F 'retained=%r %t %p'

Vous devriez voir retained=1 suivi du topic et du payload. Publiez à nouveau sans -r pendant que l'abonné est ouvert : la nouvelle ligne affiche retained=0, car il s'agit d'un message en direct et non d'un message stocké.

Pour supprimer la valeur retained, publiez un retained message vide. Le flag -n envoie un payload nul :

mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-pub-r7k2 \
  -t connectmq/demo/r7k2/thermostat/setpoint -r -n

Abonnez-vous à nouveau : plus rien ne revient. Nous détaillons le nettoyage, y compris des scripts de nettoyage par joker, dans comment supprimer un retained message.

Publier des retained messages depuis Python

Dans le code applicatif, le flag retain n'est qu'un paramètre. Voici un exemple complet avec paho-mqtt 2.x qui publie un état d'appareil retained puis le relit avec un nouveau client :

import json
import time
import uuid
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"
TOPIC = f"{PREFIX}/pump-07/state"

# 1. Publier un état retained puis se déconnecter
pub = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"pub-{uuid.uuid4().hex[:8]}")
pub.connect(BROKER, 1883, keepalive=30)
pub.loop_start()
info = pub.publish(TOPIC, json.dumps({"running": True, "rpm": 1480}), qos=1, retain=True)
info.wait_for_publish()
pub.loop_stop()
pub.disconnect()

# 2. Un nouvel abonné reçoit immédiatement la valeur stockée
def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(TOPIC, qos=1)

def on_message(client, userdata, msg):
    print(f"{msg.topic} retain={msg.retain} payload={msg.payload.decode()}")

sub = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"sub-{uuid.uuid4().hex[:8]}")
sub.on_connect = on_connect
sub.on_message = on_message
sub.connect(BROKER, 1883, keepalive=30)
sub.loop_start()
time.sleep(3)
sub.loop_stop()
sub.disconnect()

L'abonné affiche retain=True alors qu'il s'est connecté après le départ de l'éditeur. Dans un tableau de bord ou un jumeau numérique, cela signifie que l'interface peut afficher l'état actuel dès le chargement au lieu de cases vides.

Quand utiliser les retained messages MQTT

Les retained messages conviennent surtout aux données qui décrivent un état actuel plutôt qu'un événement :

  1. Statut des appareils. Indicateurs en ligne/hors ligne, version de firmware, mode de fonctionnement. Combinés au Last Will, ils offrent une présence fiable ; consultez le statut en ligne des appareils MQTT.
  2. Configuration et consignes. Un appareil qui redémarre s'abonne à son topic de configuration et reçoit ses paramètres sans appel d'API séparé.
  3. Mesures à évolution lente. Un niveau de cuve mis à jour toutes les 10 minutes est inutile pour un tableau de bord fraîchement ouvert, sauf si la dernière valeur est retained.
  4. Métadonnées de découverte. De nombreux outils domotiques et industriels publient des descripteurs retained pour que les nouveaux consommateurs trouvent les appareils.
  5. État initial d'un jumeau numérique. Un jumeau a besoin d'une image complète au démarrage, et les topics retained la fournissent avec un seul abonnement à joker.

Quand ne pas utiliser les retained messages

Le flag retain n'est ni une base de données ni une file d'attente. Évitez-le pour :

  • Les événements et les commandes. Une commande « ouvrir la vanne » retained sera rejouée à chaque appareil qui s'abonnera plus tard, y compris après un redémarrage. C'est un bug classique et dangereux. Les commandes doivent être non retained, idéalement avec une expiration ; consultez le message expiry interval MQTT.
  • L'historique de télémétrie à haute fréquence. Seul le dernier message est conservé. Si vous avez besoin d'historique, faites tourner un abonné qui écrit dans une base de séries temporelles.
  • Les alarmes qui doivent être acquittées. Une alarme retained reste visible après sa levée, sauf si quelque chose l'écrase explicitement.

Pièges et dépannage

Valeurs périmées après le retrait d'un appareil. Les retained messages vivent jusqu'à ce que quelqu'un les supprime. Ajoutez le nettoyage à votre procédure de retrait et publiez un payload retained vide pour chaque topic dont l'appareil était propriétaire.

Données fantômes issues des tests. En développement, il est facile de laisser des retained messages parasites sur les topics. Un préfixe unique par projet rend le nettoyage avec un abonné à joker bien plus simple.

Rejeux inattendus lors d'un réabonnement. Chaque SUBSCRIBE déclenche à nouveau la livraison retained, ce qui peut surprendre un code qui se réabonne à la reconnexion. MQTT 5 propose l'option d'abonnement retain handling : 0 envoie les retained messages à chaque abonnement, 1 uniquement si l'abonnement est nouveau, 2 jamais. Vérifiez si votre bibliothèque cliente l'expose.

Le flag retain semble à false sur les messages en direct. C'est attendu en MQTT 3.1.1. Si votre logique doit savoir si un message était initialement retained, utilisez MQTT 5 avec retain as published.

Valeurs retained après un redémarrage du broker. La survie des retained messages à un redémarrage dépend de la configuration de persistance du broker. Concevez vos appareils pour qu'ils republient leur état périodiquement ou à la reconnexion, afin qu'un broker redémarré soit rapidement repeuplé, plutôt que de supposer que le stockage retained est permanent.

Le comportement est défini dans la spécification OASIS MQTT 5.0 si vous voulez la formulation normative exacte.

Les retained messages sur un broker MQTT managé

Sur un broker MQTT managé, vous ne configurez pas vous-même le stockage retained, mais la conception des topics reste votre responsabilité. ConnectMQ prend en charge les retained messages en MQTT 3.1.1 et 5.0, et son portail comprend un explorateur de topics en direct et un client MQTT dans le navigateur : vous pouvez vous abonner à votre préfixe et voir les valeurs retained arriver dès la connexion. Il devient ainsi facile de repérer des données de test périmées ou un appareil qui n'a jamais fait le ménage derrière lui.

Une check-list pratique avant la mise en production :

  1. Décidez topic par topic : état (retain) ou événement (pas de retain).
  2. Ne mettez jamais de commandes en retain.
  3. Republiez l'état à chaque reconnexion, pas seulement en cas de changement.
  4. Nettoyez les topics retained lorsque des appareils sont retirés.
  5. Gardez des payloads retained compacts ; chaque nouvel abonné les reçoit tous d'un coup.

Pour aller plus loin sur le protocole dans son ensemble, le tutoriel MQTT détaille de bout en bout la publication, l'abonnement, la QoS et les sessions, et le guide du broker MQTT cloud explique comment les brokers hébergés s'intègrent dans un déploiement réel.

Démarrer avec ConnectMQ

Créez un broker gratuit sur app.connectmq.com avec le plan Serverless, sans carte bancaire. Vous obtenez en quelques minutes un nom d'utilisateur, un mot de passe et un client ID, et vous pouvez voir vos topics retained apparaître dans l'explorateur de topics ConnectMQ dès que votre premier appareil publie.

Questions fréquentes

Combien de retained messages un topic peut-il avoir ?

Exactement un. Une nouvelle publication retained sur le même topic remplace la précédente, et un payload retained vide la supprime.

Les retained messages expirent-ils ?

Pas par défaut en MQTT 3.1.1. En MQTT 5, vous pouvez définir un message expiry interval sur une publication retained, après quoi le broker cesse de la livrer aux nouveaux abonnés.

La QoS affecte-t-elle les retained messages ?

Le retained message conserve la QoS avec laquelle il a été publié, et un nouvel abonné le reçoit avec la plus faible entre cette QoS et celle de son propre abonnement.

Puis-je voir quels topics ont des retained messages ?

Abonnez-vous à un joker large comme your/prefix/# : chaque retained message situé en dessous est livré immédiatement. Sur ConnectMQ, vous pouvez faire de même depuis le client intégré au navigateur dans le portail.

Articles liés

Qui a inventé MQTT ? L'histoire, des oléoducs à l'IoT

MQTT a été inventé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nipper (Arcom) pour surveiller des oléoducs par satellite. Suivez son parcours vers l'open source, OASIS, l'ISO et les brokers MQTT managés d'aujourd'hui.

8 min de lecture

Pourquoi votre client MQTT se déconnecte sans cesse (et comment y remédier)

Les boucles de reconnexion sont l'un des problèmes MQTT les plus courants. Découvrez les cinq causes habituelles, des client ID en double aux timeouts de keep alive et aux paquets trop volumineux, et suivez une méthode de diagnostic qui identifie la vôtre.

9 min de lecture

Taille maximale d'un message MQTT : limites et stratégies pour les gros payloads

MQTT peut techniquement transporter un paquet de 256 Mo, mais les brokers, les bibliothèques clientes et les appareils imposent des limites bien plus basses. Découvrez où se trouvent les vraies limites, ce qui se passe quand on les dépasse et comment envoyer de gros payloads.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.