Le Receive Maximum MQTT est le réglage de MQTT 5 qui indique à l'autre partie combien de messages QoS 1 et QoS 2 vous acceptez d'avoir « en vol », c'est-à-dire non acquittés, en même temps. Dans ce guide, vous verrez comment cette fenêtre de contrôle de flux fonctionne dans les deux sens, pourquoi elle compte pour les microcontrôleurs et les rafales de reconnexion, et comment la configurer dans mosquitto, Python et Node.js.
Le problème que résout Receive Maximum
MQTT 3.1.1 ne disposait d'aucun contrôle de flux standard. Un broker pouvait envoyer des messages QoS 1 à un client aussi vite que la connexion TCP le permettait, et le client devait mettre chacun d'eux en mémoire tampon jusqu'à l'envoi du PUBACK. Cela fonctionne sur un serveur, mais un microcontrôleur disposant de quelques kilo-octets de RAM libre peut manquer de mémoire, perdre des messages ou planter. Le problème est le plus aigu juste après une reconnexion, lorsqu'une session persistante libère d'un coup tout un arriéré de messages en file.
Brokers et bibliothèques ont inventé leurs propres réglages « max in-flight » pour y faire face, mais ceux-ci n'étaient pas négociés : aucune des deux parties ne connaissait la limite de l'autre. MQTT 5 a standardisé l'idée sous la forme de la propriété Receive Maximum.
Comment fonctionne la fenêtre Receive Maximum MQTT
Receive Maximum est un entier sur deux octets, de 1 à 65 535, que chaque partie peut déclarer :
- Le client l'envoie dans le CONNECT : « Broker, ne m'envoie pas plus de N paquets PUBLISH QoS 1/2 non acquittés. »
- Le broker l'envoie dans le CONNACK : « Client, ne m'envoie pas plus de N paquets PUBLISH QoS 1/2 non acquittés. »
Si la propriété est absente, la valeur par défaut est 65 535, ce qui signifie en pratique « aucune limite ». La valeur 0 n'est pas autorisée.
Ce qui compte comme message en vol
| Type de paquet | Compte dans la fenêtre ? | Libéré lorsque |
|---|---|---|
| PUBLISH QoS 0 | Non | Sans objet |
| PUBLISH QoS 1 | Oui | PUBACK reçu |
| PUBLISH QoS 2 | Oui | PUBCOMP reçu (ou PUBREC avec un reason code d'erreur) |
| Retained message envoyé lors de l'abonnement | Oui, s'il est livré en QoS 1 ou 2 | Acquittement normal |
| Messages hors ligne en file | Oui, en QoS 1 ou 2 | Acquittement normal |
L'émetteur tient un compteur (la spécification l'appelle le send quota). Chaque PUBLISH QoS 1 ou 2 le décrémente ; chaque acquittement final l'incrémente. Lorsqu'il atteint zéro, l'émetteur doit cesser d'envoyer des messages QoS 1 et 2 et attendre. Il peut toujours envoyer des messages QoS 0, et la spécification l'autorise à continuer d'envoyer des PINGREQ : le keep alive n'est donc pas affecté.
Que se passe-t-il si la limite est dépassée
Si un émetteur ignore la fenêtre et que le récepteur reçoit plus de messages QoS 1/2 non acquittés qu'il n'en a annoncé, le récepteur doit se déconnecter avec le reason code 0x93 (Receive Maximum exceeded). En pratique, on le voit rarement, car les bibliothèques courantes appliquent la fenêtre automatiquement. Lorsqu'il apparaît, il signale presque toujours une implémentation cliente maison ou très ancienne.
Pourquoi c'est important pour les appareils lents
Prenons un ESP32 qui se reconnecte après une coupure Wi-Fi de 10 minutes. Sa session contient 200 mises à jour de configuration QoS 1 en file. Sans contrôle de flux, le broker peut les envoyer toutes les 200 d'un coup. Avec un Receive Maximum de 5, le broker en envoie cinq, attend les PUBACK, puis en envoie d'autres au fur et à mesure des acquittements. La consommation mémoire est bornée, le traitement suit le rythme et l'appareil reste réactif.
La fenêtre offre aussi une contre-pression naturelle aux consommateurs backend : si un worker n'envoie le PUBACK qu'après avoir écrit le message dans sa base de données, un petit Receive Maximum empêche le broker d'accumuler plus de travail que le worker ne peut en absorber. C'est un complément utile aux abonnements partagés MQTT, où plusieurs workers se partagent un même flux et où la fenêtre de chacun limite sa part de travail en vol.
Configurer Receive Maximum dans les clients
Testez sur le serveur MQTT public gratuit broker.connectmq.com avec un préfixe unique comme connectmq/demo/r2m6/.... L'espace public est ouvert à tous : utilisez des payloads factices.
mosquitto_sub
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
-i recvmax-demo-r2m6 -q 1 -v -d \
-D connect receive-maximum 5 \
-t 'connectmq/demo/r2m6/#'
La sortie de -d affiche les propriétés CONNECT que vous avez envoyées et les propriétés CONNACK renvoyées par le broker, y compris son propre Receive Maximum s'il en a défini un.
Python (paho-mqtt 2.x)
import time
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes
def on_connect(client, userdata, flags, reason_code, properties):
server_rm = getattr(properties, "ReceiveMaximum", 65535)
print("Connected:", reason_code, "| broker receive maximum:", server_rm)
client.subscribe("connectmq/demo/r2m6/#", qos=1)
def on_message(client, userdata, msg):
# Simule un appareil lent ; paho envoie le PUBACK au retour de ce callback
time.sleep(0.5)
print("Handled", msg.topic, msg.payload.decode())
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id="recvmax-py-r2m6",
protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_message = on_message
# Limite ce que *nous* envoyons en parallèle (fenêtre sortante)
client.max_inflight_messages_set(10)
# Demande au broker de limiter ce qu'*il* nous envoie (fenêtre entrante)
props = Properties(PacketTypes.CONNECT)
props.ReceiveMaximum = 5
client.connect("broker.connectmq.com", 1883, keepalive=60, properties=props)
client.loop_forever()
Publiez une rafale depuis un autre terminal et observez les messages arriver à un rythme régulier :
for i in $(seq 1 30); do
mosquitto_pub -h broker.connectmq.com -p 1883 -i burst-r2m6 \
-q 1 -t 'connectmq/demo/r2m6/burst' -m "msg $i"
done
Notez que le time.sleep dans le callback bloque aussi la boucle réseau de paho. C'est acceptable pour cette démonstration, mais en production, déplacez le travail lent dans un thread séparé et laissez la boucle libre, sinon les pings de keep alive seront retardés.
Node.js (MQTT.js v5)
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "recvmax-node-r2m6",
protocolVersion: 5,
properties: { receiveMaximum: 5 },
});
client.on("connect", (connack) => {
console.log("broker properties:", connack.properties);
client.subscribe("connectmq/demo/r2m6/#", { qos: 1 });
});
client.on("message", (topic, payload) => {
console.log(topic, payload.toString());
});
Choisir une valeur de Receive Maximum
| Client | Valeur suggérée | Pourquoi |
|---|---|---|
| Microcontrôleur (ESP32, ESP8266) | 1 à 10 | RAM limitée, traitement séquentiel |
| Passerelle Raspberry Pi | 10 à 50 | Plus de mémoire, CPU encore modeste |
| Worker backend qui écrit dans une base de données | À peu près le nombre d'écritures parallèles qu'il peut soutenir | La contre-pression correspond au débit réel |
| Tableau de bord affichant des valeurs en direct | Valeur par défaut | Trafic surtout en QoS 0, qui n'est pas limité |
Une valeur de 1 impose un traitement strictement un par un, ce qui peut aussi simplifier la logique d'ordonnancement, au prix du débit sur les liaisons à forte latence. Chaque emplacement en vol nécessite un aller-retour : sur une liaison cellulaire à forte latence, une fenêtre minuscule peut donc plafonner sensiblement le débit. Mesurez avec votre trafic réel.
Receive Maximum et ordre des messages
Une fenêtre supérieure à 1 ne remet pas en cause les garanties d'ordre de MQTT : le broker envoie toujours les messages d'un topic dans l'ordre où il les a reçus, et le client les reçoit toujours dans cet ordre. Ce qui change, c'est le nombre de messages pouvant attendre un acquittement simultanément. Si votre application acquitte les messages dans le désordre, par exemple en les confiant à un pool de threads, l'ordre de traitement relève de votre responsabilité, pas de celle du protocole. Le comportement est le même que vous vous connectiez à un broker ConnectMQ, à un Mosquitto local ou à tout autre broker MQTT 5, car la fenêtre est négociée par le protocole lui-même et non configurée d'un seul côté.
Liste de vérification pour le dépannage
- Les messages arrivent lentement après la reconnexion. C'est la fenêtre qui fonctionne. Augmentez-la si l'appareil le supporte, ou réduisez l'arriéré grâce à l'expiration des messages.
- L'appareil manque toujours de mémoire. Vérifiez si l'essentiel du trafic est en QoS 0 ; Receive Maximum ne le limite pas. Vérifiez aussi la taille maximale des paquets.
- L'éditeur se bloque. Le send quota de votre client est tombé à zéro parce que le Receive Maximum du broker est petit ou que les PUBACK sont lents. Journalisez les propriétés du CONNACK.
- Déconnexion avec 0x93. Un client a envoyé plus de messages en vol qu'autorisé ; mettez à jour ou corrigez la bibliothèque cliente.
- Le réglage n'a aucun effet. Vous vous connectez en MQTT 3.1.1. Receive Maximum n'existe qu'en MQTT 5.
Pour comprendre comment les messages en file s'accumulent au départ, consultez comment MQTT met en file les messages des clients hors ligne. Vous découvrez le protocole ? Commencez par le tutoriel MQTT.
Ajuster le contrôle de flux sur ConnectMQ
ConnectMQ prend en charge MQTT 3.1.1 et 5.0 sur TCP, TLS, WebSocket et WebSocket sécurisé : les propriétés MQTT 5 comme Receive Maximum fonctionnent donc depuis n'importe quel client. Les quotas par offre et la protection contre les rafales assurent la stabilité d'un broker MQTT dans le cloud partagé, tandis que Receive Maximum protège chacun de vos appareils. Créez un broker Serverless gratuit, sans carte bancaire, connectez-vous avec YOUR_USERNAME, YOUR_PASSWORD et YOUR_CLIENT_ID, et utilisez le client intégré au navigateur du portail pour envoyer des rafales de test à vos appareils. Pour les flottes en production, un broker MQTT managé supprime entièrement le travail d'exploitation du broker.
Questions fréquentes
Quel est le Receive Maximum MQTT par défaut ?
Si la propriété n'est pas envoyée, le Receive Maximum vaut 65 535, ce qui revient en pratique à l'absence de limite. Les clients doivent définir explicitement une valeur plus petite pour bénéficier du contrôle de flux.
Le Receive Maximum limite-t-il les messages QoS 0 ?
Non. Il ne compte que les paquets PUBLISH QoS 1 et QoS 2 qui n'ont pas encore été acquittés. Les messages QoS 0 ne sont jamais « en vol » dans ce sens.
Le Receive Maximum est-il disponible en MQTT 3.1.1 ?
Non. C'est une propriété de MQTT 5. Les clients MQTT 3.1.1 s'appuient sur des réglages « in-flight » propres à chaque bibliothèque, qui ne sont pas communiqués au broker.
Que signifie le reason code 0x93 ?
Il signifie Receive Maximum exceeded : l'émetteur avait plus de messages QoS 1 ou 2 non acquittés en vol que le récepteur ne l'autorisait, et le récepteur a donc fermé la connexion.



