Une session MQTT est l’état que le broker et le client conservent l’un sur l’autre : les topics auxquels le client s’est abonné et les messages encore en vol. Avec une session persistante, cet état survit à une déconnexion : un appareil qui disparaît du réseau quelques minutes retrouve ses abonnements et reçoit les messages qu’il a manqués. Cet article explique le fonctionnement des sessions en MQTT 3.1.1 (cleanSession) et en MQTT 5 (Clean Start plus Session Expiry Interval).
Ce que contient une session
La spécification définit l’état de session de chaque côté. Sur le broker, il comprend :
- L’existence de la session elle-même, identifiée par le client ID.
- Les abonnements du client (filtres de topic et leur QoS).
- Les messages QoS 1 et QoS 2 envoyés au client mais pas encore entièrement acquittés.
- Les messages QoS 1 et QoS 2 en attente d’envoi au client — la « file hors ligne ».
- Les messages QoS 2 reçus du client mais pas encore entièrement acquittés.
- Éventuellement, les messages QoS 0 en attente d’envoi (les brokers peuvent choisir de les mettre en file, mais le font rarement).
Le client conserve sa propre moitié : les messages QoS 1 et 2 qu’il a envoyés mais qui ne sont pas entièrement acquittés, et les messages QoS 2 reçus mais pas encore finalisés. C’est pourquoi les niveaux de QoS ne tiennent leurs garanties à travers les reconnexions que si une session persistante est utilisée.
MQTT 3.1.1 : le flag cleanSession
En MQTT 3.1.1, un seul bit du paquet CONNECT décide de tout :
| cleanSession | À la connexion | À la déconnexion |
|---|---|---|
1 (true) | Toute session existante pour ce client ID est supprimée ; une nouvelle démarre | La session est supprimée |
0 (false) | Une session existante est reprise ; sinon une nouvelle est créée | La session est conservée, et les messages QoS 1/2 destinés à ses abonnements sont mis en file |
Selon le protocole, une session persistante en 3.1.1 n’expire jamais d’elle-même. Les brokers ajoutent leurs propres limites, comme les paramètres persistent_client_expiration et max_queued_messages de Mosquitto, sans quoi les client IDs abandonnés s’accumuleraient indéfiniment. Un client ID de longueur nulle n’est autorisé qu’avec cleanSession=1, car une session impossible à identifier ne peut pas être reprise.
MQTT 5 : Clean Start et Session Expiry Interval
MQTT 5 scinde l’ancien flag en deux contrôles indépendants :
- Clean Start (un flag) — indique s’il faut supprimer toute session existante à la connexion.
- Session Expiry Interval (une propriété du
CONNECT, en secondes) — la durée pendant laquelle le broker conserve la session après la fermeture de la connexion réseau. Absente ou à0, la session se termine avec la connexion ;0xFFFFFFFFsignifie qu’elle n’expire jamais.
Cela permet des combinaisons impossibles à exprimer en 3.1.1, comme « toujours repartir de zéro, mais garder ma session une heure si je décroche » (Clean Start = 1, expiration = 3600). Le client peut aussi modifier l’expiration dans son paquet DISCONNECT, à condition de ne pas s’être connecté avec une expiration de 0.
| MQTT 3.1.1 | Paramètres MQTT 5 équivalents |
|---|---|
cleanSession = 1 | Clean Start = 1, Session Expiry Interval = 0 |
cleanSession = 0 | Clean Start = 0, Session Expiry Interval = 0xFFFFFFFF |
Les brokers MQTT 5 peuvent aussi raccourcir l’expiration demandée et annoncer la valeur réelle via une propriété Session Expiry Interval dans le CONNACK. Combinez-la avec le Message Expiry Interval par message pour que les commandes en file ne soient pas livrées des heures après avoir perdu leur pertinence. D’autres différences sont détaillées dans MQTT 5 vs 3.1.1.
Le flag Session Present
Le CONNACK du broker contient un flag Session Present qui indique au client ce qui s’est réellement passé :
1— le broker a trouvé et repris une session stockée. Les abonnements sont toujours actifs ; inutile de vous réabonner.0— aucune session n’a été reprise (Clean Start était positionné, elle a expiré ou le broker l’a perdue). Le client doit se réabonner.
Les clients robustes vérifient ce flag au lieu de faire des suppositions. Le pattern simple le plus sûr consiste à se réabonner chaque fois que Session Present vaut 0 ; se réabonner lorsqu’il vaut 1 est autorisé, mais remplace les abonnements existants et peut provoquer le renvoi des messages retenus.
Exemples
Avec la CLI Mosquitto, -c désactive la session propre et -i fixe le client ID — les deux sont nécessaires pour une session persistante :
# 1. Create the session, then press Ctrl+C
mosquitto_sub -h broker.hivemq.com -i sensor-42-sub -c -q 1 -t 'testmqtt/sess-demo/#'
# 2. While it is offline, publish with QoS 1
mosquitto_pub -h broker.hivemq.com -q 1 -t 'testmqtt/sess-demo/cmd' -m 'reboot'
# 3. Reconnect with the same ID: the queued message is delivered
mosquitto_sub -h broker.hivemq.com -i sensor-42-sub -c -q 1 -t 'testmqtt/sess-demo/#'import mqtt from 'mqtt';
const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
protocolVersion: 5,
clientId: 'sensor-42-sub',
clean: false, // Clean Start = 0
properties: { sessionExpiryInterval: 3600 },
});
client.on('connect', (connack) => {
if (!connack.sessionPresent) {
client.subscribe('testmqtt/sess-demo/#', { qos: 1 });
}
});import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
if not flags.session_present:
client.subscribe("testmqtt/sess-demo/#", qos=1)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="sensor-42-sub", clean_session=False)
client.on_connect = on_connect
client.connect("broker.hivemq.com", 1883)
client.loop_forever()Vous pouvez générer un code équivalent pour d’autres langages avec le générateur de code MQTT, et utiliser le générateur de client ID pour créer des IDs stables et uniques. Pour publier les messages de test depuis votre navigateur, utilisez le client en ligne :
Essayez-le dans le client MQTT en ligne
Combien de temps une session doit-elle vivre ?
Avec MQTT 5, vous devez choisir un Session Expiry Interval, et la bonne valeur dépend de la durée pendant laquelle le client peut raisonnablement être absent tout en ayant encore besoin de ce qu’il a manqué :
- Applications mobiles et tableaux de bord — quelques minutes. Assez pour survivre à un tunnel ou à un changement de réseau, assez peu pour que le broker ne garde pas d’état pour des utilisateurs qui ont fermé l’application.
- Appareils de terrain sur liaisons peu fiables — de quelques heures à une journée, selon la durée typique des coupures.
- Consommateurs backend — assez longtemps pour couvrir une fenêtre de déploiement ou de redémarrage, afin qu’aucun message ne soit perdu pendant le démarrage d’une nouvelle version.
Les sessions interagissent aussi avec le Last Will. En MQTT 5, le will est publié à l’expiration du Will Delay Interval ou à la fin de la session, selon ce qui arrive en premier. Un will delay court associé à une session plus longue permet à un appareil de se reconnecter discrètement après un bref incident, sans déclencher d’alerte « offline ».
Pièges courants
- Client IDs aléatoires. Beaucoup de bibliothèques génèrent un ID aléatoire à chaque démarrage, ce qui crée silencieusement une nouvelle session à chaque fois. Les sessions persistantes exigent un ID stable.
- De la QoS 0 quelque part dans la chaîne. La QoS livrée est la plus basse entre celle de la publication et celle de l’abonnement. Si l’une des deux vaut 0, les messages ne sont pas mis en file pour les clients hors ligne.
- Deux clients avec le même ID. Le broker déconnecte l’ancien lorsque le nouveau se connecte, et les deux se disputent la session. Voir les erreurs de connexion MQTT.
- Files illimitées. Un appareil hors ligne pendant des jours peut accumuler un arriéré important. Utilisez l’expiration des sessions et des messages, ainsi que les limites de file du broker, pour garder le contrôle.
- Redémarrages du broker. Les sessions ne survivent à un redémarrage du broker que s’il les persiste sur disque (pour Mosquitto,
persistence true).
Quand utiliser les sessions persistantes
Utilisez-les pour les appareils qui ne doivent manquer aucune commande ni mise à jour de configuration, et pour les consommateurs backend qui doivent traiter chaque message QoS 1. Préférez les sessions propres pour les outils éphémères, les tableaux de bord qui ne s’intéressent qu’aux dernières valeurs (les messages retenus s’en chargent) et tout ce qui se connecte avec des client IDs jetables. Sur des réseaux instables, associez une session persistante à un intervalle de keep alive raisonnable pour que les déconnexions soient détectées rapidement et que la file prenne le relais.
Questions fréquentes
Que signifie clean session à false en MQTT ?
Avec cleanSession à false en MQTT 3.1.1, le broker conserve la session du client après sa déconnexion : ses abonnements et tous les messages QoS 1 et QoS 2 qui arrivent pendant qu’il est hors ligne. Lorsque le client se reconnecte avec le même client ID, il reprend cette session et reçoit les messages en file.
Pourquoi ne reçois-je pas les messages hors ligne avec une session persistante ?
Vérifiez quatre points : le client se reconnecte avec exactement le même client ID, clean session vaut false (ou Clean Start vaut false avec un Session Expiry Interval non nul en MQTT 5), l’abonnement et la publication utilisent tous deux la QoS 1 ou 2, et le broker n’a atteint ni sa limite de file ni l’expiration de la session.
Quelle est la différence entre Clean Session et Clean Start ?
En MQTT 3.1.1, cleanSession contrôle à la fois la suppression de l’ancienne session à la connexion et la survie de la nouvelle après la déconnexion. MQTT 5 sépare les deux : Clean Start contrôle uniquement la suppression de l’ancienne session, et le Session Expiry Interval la durée de survie de la session après la déconnexion.