Fondamentaux MQTT

Les fonctionnalités de MQTT 5 qui comptent en pratique : reason codes, shared subscriptions, expiration et plus

MQTT 5 est bien plus qu'un simple changement de version. Découvrez les fonctionnalités qui changent la façon de concevoir des systèmes IoT, des reason codes et de l'expiration jusqu'aux shared subscriptions et au modèle requête/réponse, avec des exemples pratiques.

Schéma des fonctionnalités de MQTT 5, dont les shared subscriptions, les reason codes et l'expiration des messages, transitant par un broker MQTT cloud
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

MQTT 5 est la version actuelle du standard MQTT, et elle corrige bon nombre des difficultés que rencontrent les équipes qui exploitent MQTT 3.1.1 en production. Dans ce guide, vous verrez quelles fonctionnalités de MQTT 5 changent réellement le travail d'ingénierie au quotidien, vous les comparerez à la 3.1.1 et vous les essaierez vous-même sur le serveur MQTT public gratuit broker.connectmq.com, réservé aux tests, avec les outils en ligne de commande Mosquitto et Python.

Si vous découvrez le protocole, commencez par ce qu'est un broker MQTT puis revenez ici.

Pourquoi MQTT 5 existe

MQTT 3.1.1 est compact, stable et omniprésent. Mais il laisse des questions importantes sans réponse. Pourquoi ma connexion a-t-elle été refusée ? Pourquoi mon abonnement a-t-il échoué ? Comment répartir les messages d'un topic entre plusieurs workers ? Combien de temps le broker doit-il conserver ma session ou une ancienne commande ?

En 3.1.1, les réponses étaient généralement « le broker a fermé le socket » ou « mettez-le vous-même dans le payload ». MQTT 5, standardisé par l'OASIS en 2019, ajoute au protocole des retours explicites, des métadonnées et des limites tout en conservant le même modèle publish/subscribe. Vos topics, niveaux de QoS et retained messages fonctionnent exactement comme avant. La spécification complète est disponible auprès de l'OASIS.

MQTT 3.1.1 et MQTT 5 en un coup d'œil

Fonctionnalité MQTT 3.1.1 MQTT 5
Retour d'erreur Quelques codes de retour dans le CONNACK, indicateur d'échec dans le SUBACK Reason codes sur presque tous les accusés, plus des reason strings facultatives
Durée de vie de la session Clean session activée ou désactivée Session Expiry Interval en secondes
Durée de vie des messages Illimitée jusqu'à la livraison Message Expiry Interval par message
Répartition de charge Absente du standard Shared subscriptions $share/{group}/{filter}
Économie de bande passante Topic complet dans chaque PUBLISH Topic aliases (un entier au lieu de la chaîne du topic)
Métadonnées personnalisées Uniquement dans le payload User properties (paires clé/valeur)
Requête/réponse Conventions ad hoc Response Topic et Correlation Data
Contrôle de flux Propre à chaque implémentation Receive Maximum négocié dans CONNECT/CONNACK
Limites du serveur Le client doit les deviner Annoncées dans le CONNACK (Maximum QoS, Retain Available, etc.)

Reason codes : savoir pourquoi quelque chose a échoué

Pour l'exploitation, le changement le plus utile de MQTT 5 est sans conteste l'arrivée des reason codes. CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK et DISCONNECT transportent tous un code d'un octet, éventuellement accompagné d'une reason string lisible envoyée par le serveur.

Code Nom Signification typique
0x00 Success Opération acceptée
0x10 No matching subscribers Publication QoS 1/2 acceptée, mais personne n'est abonné
0x86 Bad user name or password Identifiants incorrects
0x87 Not authorized Le client n'est pas autorisé à effectuer l'action
0x89 Server busy Le broker se protège, réessayez plus tard
0x95 Packet too large Le message dépasse la taille maximale de paquet
0x97 Quota exceeded Une limite de débit ou d'usage a été atteinte

Les codes inférieurs à 0x80 indiquent un succès ; à partir de 0x80, ce sont des échecs. Pour les appareils sur le terrain, c'est un changement majeur : le firmware peut réagir différemment à « mauvais mot de passe » (arrêter et alerter) et à « serveur occupé » (temporiser et réessayer). ConnectMQ renvoie des reason codes comme 0x97 Quota exceeded et 0x89 Server busy, afin que vos clients puissent distinguer un problème de quota d'une surcharge temporaire.

Expiration de session et expiration des messages

Session Expiry Interval

En 3.1.1, une session persistante (clean session = false) vit jusqu'au retour du client, potentiellement pour toujours. MQTT 5 remplace ce mécanisme par deux paramètres : Clean Start (repartir de zéro ou reprendre) et Session Expiry Interval (nombre de secondes pendant lesquelles le broker conserve la session après la déconnexion). Un capteur qui dort pendant dix minutes peut demander une session de 15 minutes et recevoir à son réveil ses messages QoS 1 en attente, tandis que les sessions abandonnées disparaissent d'elles-mêmes.

Sur ConnectMQ, l'expiration de session est plafonnée selon l'offre ; sur le broker de test public, le maximum est de 30 minutes.

Message Expiry Interval

Un publisher peut associer à chaque message une durée de vie en secondes. Si le message attend encore dans une file ou est stocké comme retained message lorsque ce délai expire, le broker le supprime. C'est exactement ce qu'il faut pour des commandes comme « ouvrir la vanne », qu'il serait dangereux d'exécuter avec une heure de retard.

mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
  -t "connectmq/demo/a1b2/commands/valve1" -m "open" -q 1 \
  -D publish message-expiry-interval 60

Shared subscriptions : la répartition de charge intégrée

Avec un abonnement classique, chaque abonné reçoit chaque message. C'est un problème lorsqu'une seule instance backend ne parvient pas à suivre des milliers d'appareils. Les shared subscriptions de MQTT 5 permettent à plusieurs clients de rejoindre un groupe ; le broker livre chaque message à un seul membre du groupe.

La syntaxe est $share/{group}/{filter}. Rien ne change côté publishers : ils publient toujours sur le topic simple.

Essayez : deux workers partageant un même topic

Ouvrez deux terminaux et lancez deux consommateurs dans le même groupe workers. Remplacez a1b2 par votre propre identifiant aléatoire, car la zone publique est lisible par tous.

# Terminal 1
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-w1 \
  -t '$share/workers/connectmq/demo/a1b2/jobs' -v

# Terminal 2
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-w2 \
  -t '$share/workers/connectmq/demo/a1b2/jobs' -v

Publiez maintenant six tâches depuis un troisième terminal :

for i in 1 2 3 4 5 6; do
  mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
    -t "connectmq/demo/a1b2/jobs" -m "job-$i" -q 1
done

Lorsque nous avons exécuté ce test sur broker.connectmq.com, le worker 1 a reçu job-1, job-3, job-5 et le worker 2 job-2, job-4, job-6. Chaque tâche a été traitée une seule fois, et ajouter un troisième worker répartit davantage la charge sans toucher aux publishers. Sous bash, les apostrophes autour du topic sont importantes pour que le shell n'interprète pas $share.

Usages typiques : services d'ingestion mis à l'échelle horizontalement, processeurs de commandes et tout consommateur exécuté sous forme de plusieurs réplicas de conteneur.

Topic aliases : des paquets plus petits sur les liaisons contraintes

Les topics industriels peuvent être longs, par exemple acme/izmir/machining/line1/cnc1/telemetry. Envoyer cette chaîne dans chaque PUBLISH gaspille de la bande passante sur les liaisons cellulaires ou satellites. Avec un topic alias, le client envoie une fois le topic complet accompagné d'un alias entier, puis uniquement le numéro d'alias par la suite. Chaque partie annonce dans CONNECT et CONNACK le nombre d'alias qu'elle accepte (Topic Alias Maximum). La plupart des bibliothèques clientes gèrent les alias pour vous une fois la fonctionnalité activée.

User properties : des métadonnées sans toucher au payload

Les user properties sont des paires clé/valeur UTF-8 arbitraires attachées à un paquet. Utilisez-les pour indiquer un type de contenu, une version de schéma, des identifiants de trace ou la version du firmware de l'émetteur, tandis que le payload reste une simple mesure de capteur.

mosquitto_pub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-pub \
  -t "connectmq/demo/a1b2/sensors/t1" -m '{"temperature":22.4}' \
  -D publish user-property schema v2 -D publish user-property fw 1.4.0

Un abonné peut les afficher avec mosquitto_sub -V mqttv5 -F "%t %p %P".

Requête/réponse avec Response Topic et Correlation Data

De nombreux flux IoT sont en réalité des appels RPC : « lis ta configuration », « redémarre », « donne-moi les 10 dernières valeurs ». MQTT 5 standardise ce schéma :

  1. Le demandeur s'abonne à son propre topic de réponse.
  2. Il publie la requête avec une propriété Response Topic pointant vers ce topic de réponse, et des Correlation Data qui identifient la requête.
  3. Le répondeur répond sur le response topic et recopie les correlation data.

Comme le response topic est transmis aux abonnés, le répondeur n'a besoin d'aucune connaissance de routage codée en dur. Vous pouvez voir arriver les propriétés avec :

mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 -i demo-a1b2-s \
  -t "connectmq/demo/a1b2/#" -F "%t %p | response=%R props=%P"

Contrôle de flux et limites annoncées par le serveur

Receive Maximum

Receive Maximum plafonne le nombre de messages QoS 1 et QoS 2 pouvant être en transit simultanément (envoyés mais pas encore acquittés). Le client indique sa limite au serveur dans le CONNECT, et le serveur indique la sienne au client dans le CONNACK. Un petit microcontrôleur peut fixer une valeur basse pour ne jamais être submergé, et le broker peut se protéger d'un client qui publie plus vite qu'il ne peut acquitter. Pour en savoir plus sur les accusés de réception, consultez Les niveaux de QoS MQTT expliqués.

Les limites dans le CONNACK

En 3.1.1, un client découvrait les limites en échouant. En MQTT 5, le serveur les annonce dans les propriétés du CONNACK, notamment Maximum QoS, Retain Available, Wildcard Subscription Available, Shared Subscription Available, Receive Maximum et Topic Alias Maximum. Un client bien écrit les lit une fois et s'adapte, par exemple en redescendant en QoS 1 si la QoS 2 n'est pas proposée sur l'offre en cours.

MQTT 5 en Python avec Paho 2.x

Le script suivant se connecte en MQTT 5, affiche les limites annoncées dans le CONNACK et effectue un aller-retour requête/réponse complet en utilisant l'expiration des messages, les user properties, le response topic et les correlation data.

import time
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties

BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/a1b2"          # utilisez votre propre ID aléatoire
REQ_TOPIC = f"{PREFIX}/rpc/request"
RESP_TOPIC = f"{PREFIX}/rpc/response"


def on_connect(client, userdata, flags, reason_code, properties):
    print("CONNACK:", reason_code)
    for name in ("MaximumQoS", "RetainAvailable", "ReceiveMaximum",
                 "TopicAliasMaximum", "SharedSubscriptionAvailable"):
        if hasattr(properties, name):
            print(f"  {name} = {getattr(properties, name)}")
    client.subscribe(REQ_TOPIC, qos=1)
    client.subscribe(RESP_TOPIC, qos=1)


def on_message(client, userdata, msg):
    props = msg.properties
    if msg.topic == REQ_TOPIC:
        # Côté répondeur : répondre sur le topic demandé, renvoyer les correlation data
        reply = Properties(PacketTypes.PUBLISH)
        reply.CorrelationData = props.CorrelationData
        client.publish(props.ResponseTopic, b'{"uptime": 3600}', qos=1,
                       properties=reply)
    elif msg.topic == RESP_TOPIC:
        print("Response:", msg.payload.decode(),
              "correlation:", props.CorrelationData.decode())


connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 600   # conserver la session 10 minutes
connect_props.ReceiveMaximum = 10           # 10 messages entrants non acquittés au maximum

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="demo-a1b2-py", protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, clean_start=True, properties=connect_props)
client.loop_start()
time.sleep(2)

request = Properties(PacketTypes.PUBLISH)
request.ResponseTopic = RESP_TOPIC
request.CorrelationData = uuid.uuid4().hex.encode()
request.MessageExpiryInterval = 30
request.UserProperty = [("schema", "v1"), ("app", "blog-demo")]
client.publish(REQ_TOPIC, b'{"cmd": "status"}', qos=1, properties=request)

time.sleep(3)
client.loop_stop()
client.disconnect()

Dans un vrai système, le demandeur et le répondeur sont des clients distincts, mais le code reste le même. En production, connectez-vous à votre propre broker avec YOUR_USERNAME, YOUR_PASSWORD et YOUR_CLIENT_ID fournis par le portail, idéalement en TLS sur le port 8883 (voir Sécurité MQTT : les bonnes pratiques).

La prise en charge de MQTT 5 dans ConnectMQ

Les brokers ConnectMQ parlent à la fois MQTT 3.1.1 et MQTT 5.0 sur TCP, TLS et WebSocket : anciens et nouveaux appareils peuvent donc partager le même broker. Les fonctionnalités MQTT 5 actuellement implémentées sont les suivantes :

Fonctionnalité Prise en charge par ConnectMQ
Reason codes Oui, par exemple 0x97 Quota exceeded et 0x89 Server busy
Expiration de session Oui, plafonnée selon l'offre (30 minutes sur le broker de test public)
Message expiry interval Oui
Shared subscriptions Oui, $share/{group}/{filter} ; sur le broker de test public et à partir de l'offre Serverless (Paid)
Topic alias Oui
Response topic (requête/réponse) Oui, transmis aux abonnés
Limites dans le CONNACK Maximum QoS, Retain Available, Wildcard et Shared Subscription Available, Receive Maximum
Retained messages Oui

L'extension VS Code de ConnectMQ affiche directement les reason codes CONNACK, SUBACK et PUBACK, ce qui est pratique pour comprendre pourquoi un abonnement a été refusé.

Démarrer avec ConnectMQ

Vous pouvez essayer tous les exemples de cet article sur broker.connectmq.com sans compte. Quand vous êtes prêt à disposer de votre propre broker isolé avec identifiants, inscrivez-vous sur app.connectmq.com : l'offre Serverless est gratuite, ne demande pas de carte bancaire et vous fournit un broker en quelques minutes. Comparez les options dans Qu'est-ce qu'un broker MQTT managé ?.

Questions fréquentes

MQTT 5 est-il rétrocompatible avec MQTT 3.1.1 ?

Le format sur le réseau diffère : un client choisit donc une version lorsqu'il se connecte. Un broker qui prend en charge les deux, comme ConnectMQ, permet aux clients MQTT 3.1.1 et MQTT 5 d'échanger des messages sur les mêmes topics.

Ai-je besoin de MQTT 5 pour les shared subscriptions ?

Les shared subscriptions sont définies dans le standard MQTT 5. Connectez-vous en MQTT 5 (par exemple avec -V mqttv5 dans les outils Mosquitto) et abonnez-vous à $share/{group}/{filter} pour obtenir une livraison répartie.

Quelle est la différence entre l'expiration de session et l'expiration des messages ?

L'expiration de session détermine combien de temps le broker conserve la session d'un client déconnecté et ses messages en attente. L'expiration des messages détermine combien de temps un message donné reste valide avant que le broker ne le supprime.

Quelle fonctionnalité de MQTT 5 adopter en premier ?

Commencez par les reason codes, car ils rendent les échecs visibles sans aucun coût. Ajoutez ensuite l'expiration de session pour les appareils en veille et les shared subscriptions pour les services backend qui doivent monter en charge.

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.