Fondamentaux MQTT

Les niveaux de QoS MQTT expliqués : QoS 0, 1 et 2 avec flux de paquets et exemples

Un guide pratique de la QoS MQTT : comment fonctionnent les QoS 0, 1 et 2 sur le réseau, pourquoi la QoS livrée peut être inférieure à celle demandée, comment les sessions mettent les messages en file d'attente et quel niveau choisir pour chaque cas d'usage.

Schéma des flux de paquets QoS MQTT 0, 1 et 2 entre un client et un broker MQTT
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

La QoS MQTT (Quality of Service, ou qualité de service) est la garantie de livraison qu'un client demande lorsqu'il publie ou s'abonne. Dans ce guide, vous verrez précisément quels paquets échangent les QoS 0, 1 et 2, pourquoi la QoS qui atteint un abonné peut être inférieure à celle utilisée à la publication, comment les sessions mettent les messages en file d'attente pour les clients hors ligne, et comment tester tout cela en Python sur le serveur MQTT public gratuit broker.connectmq.com.

Si vous découvrez MQTT, commencez par Qu'est-ce qu'un broker MQTT ? puis revenez ici.

Ce que garantit réellement la QoS MQTT

MQTT repose sur TCP : au sein d'une même connexion, les octets ne sont ni perdus ni réordonnés. La QoS concerne autre chose : ce qui se passe lorsqu'une connexion tombe au milieu d'une livraison, et si le destinataire risque de recevoir deux fois le même message.

Deux points sont souvent mal compris :

  • La QoS s'applique saut par saut, pas de bout en bout. La QoS du publisher régit le trajet du publisher vers le broker. La QoS de l'abonnement régit le trajet du broker vers l'abonné. Le broker sert d'intermédiaire pour les deux.
  • Une QoS plus élevée n'est pas « meilleure » par défaut. Chaque niveau ajoute des paquets, de l'état et de la latence. Le bon choix dépend de ce que vous coûte un message perdu ou dupliqué.
Niveau Nom Garantie Paquets par message (un trajet) Doublons possibles ?
QoS 0 At most once (au plus une fois) Au mieux, sans accusé de réception 1 Non, mais une perte est possible
QoS 1 At least once (au moins une fois) Livré, peut être répété 2 Oui
QoS 2 Exactly once (exactement une fois) Livré une seule fois, sans doublon 4 Non

QoS 0 : au plus une fois

La QoS 0 fonctionne en « fire and forget ». L'émetteur écrit un paquet PUBLISH sur le socket et l'oublie aussitôt. Il n'y a ni identifiant de paquet ni accusé de réception.

Publisher                     Broker
    |                            |
    |------ PUBLISH (QoS 0) ---->|
    |                            |   (no reply, nothing stored)

Si la connexion TCP se rompt alors que le paquet est encore dans un buffer du système d'exploitation, le message est perdu et personne n'en sait rien. Cela peut sembler gênant, mais pour une mesure de température envoyée toutes les deux secondes, la mesure suivante remplace de toute façon celle qui a été perdue. La QoS 0 offre la latence la plus faible et le moins de surcharge sur les appareils contraints.

QoS 1 : au moins une fois

En QoS 1, l'émetteur attribue un identifiant de paquet et conserve le message jusqu'à ce que le destinataire réponde par un PUBACK portant le même identifiant.

Publisher                     Broker
    |                            |
    |-- PUBLISH (QoS 1, id=7) -->|   broker stores and forwards
    |<------- PUBACK (id=7) -----|
    |                            |   publisher deletes message 7

Si le PUBACK n'arrive jamais (par exemple parce que la connexion tombe), l'émetteur renvoie le PUBLISH avec l'indicateur DUP après s'être reconnecté. Le piège : le destinataire a peut-être déjà traité la première copie, et il voit alors le message deux fois. C'est pourquoi la QoS 1 signifie au moins une fois.

La QoS 1 est la bête de somme de la plupart des systèmes IoT. Rendez vos consommateurs idempotents (par exemple en incluant un identifiant de message ou un horodatage dans le payload et en ignorant les répétitions), et la QoS 1 suffit généralement.

QoS 2 : exactement une fois

La QoS 2 utilise un échange en quatre étapes afin que les deux parties s'accordent sur le fait que le message a été livré exactement une fois.

Publisher                       Broker
    |                              |
    |--- PUBLISH (QoS 2, id=9) --->|   broker stores id 9, does not forward twice
    |<------- PUBREC (id=9) -------|   "received"
    |-------- PUBREL (id=9) ------>|   "release it, I will not resend"
    |<------- PUBCOMP (id=9) ------|   "complete", both sides drop id 9

Le rôle de chaque étape :

  1. PUBLISH : l'émetteur stocke le message et l'envoie avec un identifiant de paquet.
  2. PUBREC : le destinataire enregistre l'identifiant. Si un PUBLISH en double portant le même ID arrive, il est reconnu et n'est pas livré une seconde fois.
  3. PUBREL : l'émetteur supprime le message et ne garde plus en mémoire que l'identifiant.
  4. PUBCOMP : le destinataire oublie l'identifiant. L'échange est terminé.

Le coût : deux allers-retours par message et un état conservé des deux côtés jusqu'à la fin du flux. Utilisez la QoS 2 lorsqu'un doublon causerait un réel préjudice et que vous ne pouvez pas rendre le consommateur idempotent, par exemple pour une commande qui incrémente un compteur ou déclenche un événement de facturation.

Rétrogradation de la QoS MQTT : pourquoi vous n'obtenez pas toujours la QoS demandée

La QoS reçue par un abonné n'est pas simplement celle utilisée par le publisher. Trois valeurs interagissent.

QoS effective = min(QoS de publication, QoS d'abonnement)

Lorsque le broker transmet un message, il utilise la plus faible entre la QoS du PUBLISH d'origine et la QoS accordée pour l'abonnement.

QoS du publisher QoS de l'abonnement Livré à l'abonné
0 2 0
1 2 1
2 1 1
2 0 0
2 2 2

Si vous avez besoin d'une livraison exactement une fois de bout en bout, le publisher et chaque abonné doivent donc utiliser la QoS 2. Un seul abonnement en QoS 0 transforme discrètement le flux de cet abonné en « au mieux ».

La Maximum QoS du broker (MQTT 5)

En MQTT 5, le broker peut annoncer une Maximum QoS dans son paquet CONNACK. Si cette propriété est absente, le client peut supposer que la QoS 2 est prise en charge. Si elle est présente, le client ne doit pas publier au-delà de ce niveau, et le broker n'accordera pas d'abonnement à un niveau supérieur (le SUBACK vous indique la QoS accordée).

Sur ConnectMQ, cela dépend de l'endroit où vous vous connectez :

Environnement Maximum QoS
Zone de test publique de broker.connectmq.com QoS 2
Offre Serverless (Free) QoS 1
Offre Serverless (Paid) QoS 2
Dedicated, BYOC, Self Managed Enterprise QoS 2

Vérifiez toujours la QoS accordée dans le SUBACK au lieu de la supposer. La plupart des bibliothèques clientes l'exposent dans le callback d'abonnement. La spécification MQTT 5 sur docs.oasis-open.org décrit les règles exactes. Pour un tour d'horizon des autres propriétés du CONNACK, consultez Les fonctionnalités de MQTT 5.

Sessions, expiration de session et file d'attente hors ligne

La QoS ne protège les messages lors d'une déconnexion que si la session survit à cette déconnexion. La session est l'état que le broker conserve pour un client : ses abonnements, les messages QoS 1/2 en cours de transmission et les messages mis en file d'attente pendant qu'il est hors ligne.

  • MQTT 3.1.1 utilise l'indicateur Clean Session. cleanSession=true supprime la session à la déconnexion. cleanSession=false demande au broker de la conserver.
  • MQTT 5 scinde ce rôle en Clean Start (repartir de zéro ou non à la connexion) et Session Expiry Interval (nombre de secondes pendant lesquelles la session survit après la déconnexion).

Tant qu'une session persistante existe et que le client est hors ligne, le broker met en file d'attente les messages QoS 1 et QoS 2 qui correspondent à ses abonnements. Les messages QoS 0 ne sont pas mis en file d'attente pour les clients hors ligne. Lorsque le client se reconnecte avec le même client ID et sans clean start, les messages en attente sont livrés.

Subscriber (id=sensor-reader)           Broker
    |-- CONNECT clean_start=0, expiry=600 -->|
    |-- SUBSCRIBE plant/# QoS 1 ------------>|
    |  ... connection lost ...               |
    |                                         |  PUBLISH plant/a QoS 1  -> queued
    |                                         |  PUBLISH plant/b QoS 0  -> dropped
    |-- CONNECT clean_start=0 --------------->|
    |<-- CONNACK session_present=1 -----------|
    |<-- PUBLISH plant/a ---------------------|

Sur ConnectMQ, l'expiration de session est plafonnée selon l'offre, et dans la zone de test publique, les sessions vivent jusqu'à 30 minutes. Notez aussi que les sessions sont conservées en mémoire : elles ne survivent pas à un redémarrage du broker. Concevez donc vos flux critiques pour qu'ils tolèrent une reconnexion avec session_present=0.

Comment choisir le bon niveau de QoS MQTT

Cas d'usage QoS recommandée Pourquoi
Télémétrie haute fréquence (température, vibrations) 0 L'échantillon suivant remplace celui qui est perdu ; surcharge minimale
État des appareils, alarmes, événements 1 Doit arriver ; les doublons sont faciles à ignorer
Commandes d'actionneurs idempotentes (« régler la vanne à 40 % ») 1 Répéter la même commande est sans conséquence
Commandes non idempotentes (« incrémenter le compteur », « distribuer ») 2 Un doublon changerait le résultat
Événements de facturation, de comptage ou de transaction 2 (ou 1 avec des ID de déduplication) Comptabilisation exactement une fois

Une règle pratique : utilisez par défaut la QoS 1 avec des consommateurs idempotents, descendez en QoS 0 pour les données à haut débit dont vous pouvez vous permettre de perdre une partie, et réservez la QoS 2 aux quelques types de messages pour lesquels un doublon est un bug.

En pratique : QoS MQTT 1 et 2 en Python

Le script suivant utilise paho-mqtt 2.x et la zone publique de broker.connectmq.com (sans nom d'utilisateur ni mot de passe). Il s'abonne en QoS 2, publie un message en QoS 1 et un autre en QoS 2, et journalise les accusés de réception. Installez la bibliothèque avec pip install "paho-mqtt>=2.0".

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

BROKER = "broker.connectmq.com"
UID = uuid.uuid4().hex[:8]
TOPIC = f"connectmq/demo/{UID}/qos"

def on_connect(client, userdata, flags, reason_code, properties):
    print("CONNACK:", reason_code)
    if properties is not None and hasattr(properties, "MaximumQoS"):
        print("Broker Maximum QoS:", properties.MaximumQoS)
    client.subscribe(f"{TOPIC}/#", qos=2)

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    print("SUBACK granted:", [rc.value for rc in reason_code_list])

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

def on_publish(client, userdata, mid, reason_code, properties):
    print(f"Publish flow complete for mid={mid}")

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"qos-demo-{UID}",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_publish = on_publish

client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
time.sleep(2)

client.publish(f"{TOPIC}/one", "hello at least once", qos=1).wait_for_publish()
client.publish(f"{TOPIC}/two", "hello exactly once", qos=2).wait_for_publish()

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

En QoS 1, on_publish se déclenche à l'arrivée du PUBACK. En QoS 2, il ne se déclenche qu'après le PUBCOMP, à la fin de l'échange en quatre étapes. Si aucune ligne Maximum QoS n'est affichée, c'est que le broker n'a pas envoyé la propriété, ce qui signifie que la QoS 2 est autorisée.

Observer les paquets avec la CLI Mosquitto

Les outils en ligne de commande Eclipse Mosquitto affichent chaque paquet avec -d, ce qui rend visibles les flux décrits ci-dessus. Dans un terminal :

mosquitto_sub -h broker.connectmq.com -p 1883 -i qos-sub-a1b2 -t "connectmq/demo/a1b2/#" -q 2 -v -d

Dans un second terminal, publiez en QoS 1 puis en QoS 2 :

mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q1" -q 1 -m "hello1" -d
mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q2" -q 2 -m "hello2" -d

La sortie du publisher montre exactement les séquences décrites plus haut :

Client qos-pub-a1b2 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/a1b2/q1', ... (6 bytes))
Client qos-pub-a1b2 received PUBACK (Mid: 1, RC:0)
...
Client qos-pub-a1b2 sending PUBLISH (d0, q2, r0, m1, 'connectmq/demo/a1b2/q2', ... (6 bytes))
Client qos-pub-a1b2 received PUBREC (Mid: 1)
Client qos-pub-a1b2 sending PUBREL (m1)
Client qos-pub-a1b2 received PUBCOMP (Mid: 1, RC:0)

Remplacez a1b2 par votre propre chaîne aléatoire. Tout ce qui se trouve dans la zone publique est lisible par n'importe qui : n'y publiez jamais de données sensibles. Pour expérimenter la rétrogradation, abonnez-vous avec -q 0 et publiez avec -q 2 : la sortie de débogage de l'abonné affichera q0 sur le PUBLISH livré. Vous trouverez d'autres astuces dans notre article sur le serveur MQTT public gratuit.

Les erreurs de QoS les plus courantes

  • Supposer une QoS 2 de bout en bout alors qu'un abonné utilise la QoS 0. C'est le maillon le plus faible qui l'emporte.
  • Utiliser la QoS 2 pour de la télémétrie à haut débit. Quatre paquets par message et par trajet s'accumulent vite, et la fenêtre de messages en transit (Receive Maximum) se remplit.
  • Des client IDs aléatoires avec des sessions persistantes. La file d'attente hors ligne ne fonctionne que si le client se reconnecte avec le même client ID. Un nouvel ID aléatoire crée une nouvelle session vide.
  • Ignorer la QoS accordée dans le SUBACK. Sur une offre plafonnée à la QoS 1, un abonnement en QoS 2 est accordé en QoS 1.

Démarrer avec ConnectMQ

Le serveur public est idéal pour apprendre la QoS MQTT, mais le trafic de production doit passer par un broker MQTT managé privé avec identifiants. Inscrivez-vous gratuitement sur app.connectmq.com (offre Serverless, sans carte bancaire), créez un broker et utilisez le nom d'utilisateur, le mot de passe et le client ID générés. Passez à Serverless (Paid) ou Dedicated lorsque vous avez besoin de la QoS 2, de davantage de connexions ou de messages plus volumineux.

Questions fréquentes

Quel est le niveau de QoS MQTT par défaut ?

La plupart des bibliothèques clientes utilisent par défaut la QoS 0, aussi bien pour publier que pour s'abonner. Définissez explicitement la QoS dans votre code pour que le comportement soit clair pour quiconque le lit.

La QoS 2 ralentit-elle MQTT ?

Oui. La QoS 2 nécessite quatre paquets et deux allers-retours par message sur chaque trajet, contre deux paquets pour la QoS 1 et un seul pour la QoS 0. Pour la plupart des télémesures, la QoS 0 ou 1 offre un meilleur débit.

Pourquoi mon abonné a-t-il reçu une QoS 1 alors que j'ai publié en QoS 2 ?

La QoS livrée est le minimum entre la QoS de publication et la QoS accordée à l'abonnement. Votre abonnement a été accordé en QoS 1, soit parce que vous l'avez demandé, soit parce que la Maximum QoS du broker est 1, comme sur l'offre ConnectMQ Serverless (Free).

Les messages QoS 0 sont-ils mis en file d'attente pour les clients hors ligne ?

Non. Les brokers ne mettent en file d'attente que les messages QoS 1 et QoS 2 pour les clients disposant d'une session persistante. Les messages QoS 0 destinés à un client hors ligne sont abandonnés.

Puis-je utiliser la QoS 2 sur broker.connectmq.com ?

Oui. La zone publique anonyme prend en charge les QoS 0, 1 et 2. Les brokers privés prennent en charge la QoS 2 à partir de l'offre Serverless (Paid), tandis que l'offre Serverless gratuite est limitée à la QoS 1.

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.