MQTT Receive Maximum ist die Einstellung in MQTT 5, mit der Sie der Gegenseite mitteilen, wie viele QoS-1- und QoS-2-Nachrichten gleichzeitig „in flight“, also unbestätigt, unterwegs sein dürfen. In diesem Leitfaden erfahren Sie, wie dieses Flusskontrollfenster in beide Richtungen funktioniert, warum es für Mikrocontroller und Nachrichtenwellen nach einem Reconnect wichtig ist und wie Sie es in mosquitto, Python und Node.js setzen.
Welches Problem Receive Maximum löst
MQTT 3.1.1 hatte keine standardisierte Flusskontrolle. Ein Broker konnte QoS-1-Nachrichten so schnell an einen Client schicken, wie es die TCP-Verbindung zuließ, und der Client musste jede einzelne puffern, bis er das PUBACK gesendet hatte. Auf einem Server klappt das, aber einem Mikrocontroller mit wenigen Kilobyte freiem RAM kann der Speicher ausgehen, er verliert Nachrichten oder stürzt ab. Am schlimmsten ist es direkt nach einem Reconnect, wenn eine Persistent Session einen Rückstau gepufferter Nachrichten auf einmal freigibt.
Broker und Bibliotheken erfanden eigene „Max in-flight“-Einstellungen, um damit umzugehen, doch diese wurden nicht ausgehandelt, sodass keine Seite das Limit der anderen kannte. MQTT 5 hat die Idee als Property Receive Maximum standardisiert.
So funktioniert das Fenster von MQTT Receive Maximum
Receive Maximum ist eine Zwei-Byte-Ganzzahl von 1 bis 65.535, die jede Seite angeben kann:
- Der Client sendet sie im CONNECT: „Broker, schick mir nicht mehr als N unbestätigte QoS-1/2-PUBLISH-Pakete.“
- Der Broker sendet sie im CONNACK: „Client, schick mir nicht mehr als N unbestätigte QoS-1/2-PUBLISH-Pakete.“
Fehlt die Property, gilt der Standardwert 65.535, was praktisch „kein Limit“ bedeutet. Der Wert 0 ist nicht erlaubt.
Was als „in flight“ zählt
| Pakettyp | Zählt gegen das Fenster? | Freigegeben, wenn |
|---|---|---|
| QoS-0-PUBLISH | Nein | Nicht zutreffend |
| QoS-1-PUBLISH | Ja | PUBACK empfangen |
| QoS-2-PUBLISH | Ja | PUBCOMP empfangen (oder PUBREC mit Fehler-Reason-Code) |
| Retained Message, die beim Abonnieren gesendet wird | Ja, bei Zustellung mit QoS 1 oder 2 | Normale Bestätigung |
| Gepufferte Offline-Nachrichten | Ja, bei QoS 1 oder 2 | Normale Bestätigung |
Der Sender führt einen Zähler (die Spezifikation nennt ihn Send Quota). Jedes QoS-1- oder QoS-2-PUBLISH verringert ihn, jede abschließende Bestätigung erhöht ihn. Erreicht er null, muss der Sender das Senden von QoS-1- und QoS-2-Nachrichten einstellen und warten. QoS-0-Nachrichten darf er weiterhin senden, und laut Spezifikation darf er auch weiter PINGREQ schicken, sodass Keep Alive unbeeinträchtigt bleibt.
Was passiert, wenn das Limit überschritten wird
Ignoriert ein Sender das Fenster und erhält der Empfänger mehr unbestätigte QoS-1/2-Nachrichten, als er angekündigt hat, sollte der Empfänger die Verbindung mit dem Reason Code 0x93 (Receive Maximum exceeded) trennen. In der Praxis sieht man das selten, weil gängige Bibliotheken das Fenster automatisch einhalten. Wenn es doch auftritt, deutet es fast immer auf eine selbst geschriebene oder sehr alte Client-Implementierung hin.
Warum es für langsame Geräte wichtig ist
Nehmen Sie einen ESP32, der sich nach einem zehnminütigen WLAN-Ausfall neu verbindet. Seine Session hält 200 gepufferte QoS-1-Konfigurationsupdates. Ohne Flusskontrolle kann der Broker alle 200 auf einmal schicken. Mit einem Receive Maximum von 5 sendet der Broker fünf, wartet auf die PUBACKs und schickt mit jeder eintreffenden Bestätigung weitere. Der Speicherverbrauch bleibt begrenzt, die Verarbeitung kommt hinterher und das Gerät bleibt reaktionsfähig.
Das Fenster liefert auch natürlichen Gegendruck (Back-Pressure) für Backend-Consumer: Sendet ein Worker das PUBACK erst, nachdem er eine Nachricht in seine Datenbank geschrieben hat, verhindert ein kleines Receive Maximum, dass der Broker mehr Arbeit auftürmt, als der Worker bewältigen kann. Ein typisches Beispiel aus der Fertigung ist ein Historian- oder MES-Konnektor, der Maschinendaten aus dem Unified Namespace (UNS) eines Werks in eine Datenbank schreibt. Das ergänzt MQTT Shared Subscriptions sinnvoll, bei denen sich mehrere Worker einen Nachrichtenstrom teilen und das Fenster jedes Workers seinen Anteil an unbestätigter Arbeit begrenzt.
Receive Maximum in Clients setzen
Testen Sie gegen den öffentlichen MQTT-Broker unter broker.connectmq.com mit einem eindeutigen Präfix wie connectmq/demo/r2m6/.... Der öffentliche MQTT-Broker ist für Tests gedacht und für alle offen, verwenden Sie also Dummy-Payloads.
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/#'
Die Ausgabe von -d zeigt die gesendeten CONNECT-Properties und die vom Broker zurückgegebenen CONNACK-Properties, einschließlich seines eigenen Receive Maximum, falls er eines gesetzt hat.
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):
# Langsames Gerät simulieren; paho sendet PUBACK, nachdem dieser Callback zurückkehrt
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
# Begrenzen, was *wir* gleichzeitig senden (ausgehendes Fenster)
client.max_inflight_messages_set(10)
# Den Broker bitten zu begrenzen, was *er* an uns sendet (eingehendes Fenster)
props = Properties(PacketTypes.CONNECT)
props.ReceiveMaximum = 5
client.connect("broker.connectmq.com", 1883, keepalive=60, properties=props)
client.loop_forever()
Veröffentlichen Sie aus einem anderen Terminal eine Nachrichtenwelle und beobachten Sie, wie die Nachrichten in gleichmäßigem Tempo eintreffen:
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
Beachten Sie, dass time.sleep im Callback auch die Netzwerkschleife von paho blockiert. Für diese Demonstration ist das in Ordnung, in der Produktion sollten Sie langsame Arbeit aber in einen separaten Thread auslagern und die Schleife frei halten, sonst verzögern sich die Keep-Alive-Pings.
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());
});
Den passenden Wert für Receive Maximum wählen
| Client | Empfohlener Wert | Warum |
|---|---|---|
| Mikrocontroller (ESP32, ESP8266) | 1 bis 10 | Begrenzter RAM, sequenzielle Verarbeitung |
| Raspberry-Pi- oder Industrie-Edge-Gateway | 10 bis 50 | Mehr Speicher, aber weiterhin bescheidene CPU |
| Backend-Worker, der in eine Datenbank schreibt | Etwa die Zahl paralleler Schreibvorgänge, die er dauerhaft schafft | Gegendruck entspricht dem realen Durchsatz |
| Dashboard mit Live-Werten | Standardwert | Überwiegend QoS-0-Verkehr, der nicht begrenzt wird |
Ein Wert von 1 erzwingt strikte Einzelverarbeitung, was auch die Logik für die Reihenfolge vereinfachen kann, kostet aber auf Verbindungen mit hoher Latenz Durchsatz. Jeder Slot benötigt einen Roundtrip, sodass ein winziges Fenster auf einer Mobilfunkverbindung mit hoher Latenz den Durchsatz spürbar deckeln kann. Messen Sie mit Ihrem realen Verkehr.
Receive Maximum und Nachrichtenreihenfolge
Ein Fenster größer als 1 bricht die Reihenfolgegarantien von MQTT nicht: Der Broker sendet die Nachrichten eines Topics weiterhin in der Reihenfolge, in der er sie empfangen hat, und der Client empfängt sie in dieser Reihenfolge. Was sich ändert, ist nur, wie viele gleichzeitig auf eine Bestätigung warten können. Bestätigt Ihre Anwendung Nachrichten in anderer Reihenfolge, etwa weil sie sie an einen Thread-Pool übergibt, liegt die Verarbeitungsreihenfolge in Ihrer Verantwortung, nicht in der des Protokolls. Das Verhalten ist dasselbe, ob Sie sich mit einem ConnectMQ-Broker, einem lokalen Mosquitto oder einem anderen MQTT-5-Broker verbinden, denn das Fenster wird vom Protokoll selbst ausgehandelt und nicht einseitig konfiguriert.
Checkliste zur Fehlerbehebung
- Nachrichten kommen nach dem Reconnect langsam an. Das ist das Fenster bei der Arbeit. Erhöhen Sie es, wenn das Gerät damit zurechtkommt, oder verkleinern Sie den Rückstau mit Message Expiry.
- Dem Gerät geht trotzdem der Speicher aus. Prüfen Sie, ob der Großteil des Verkehrs QoS 0 ist; den begrenzt Receive Maximum nicht. Prüfen Sie außerdem die maximale Paketgröße.
- Der Publisher stockt. Die Send Quota Ihres Clients ist auf null gefallen, weil das Receive Maximum des Brokers klein ist oder PUBACKs langsam kommen. Protokollieren Sie die CONNACK-Properties.
- Trennung mit 0x93. Ein Client hat mehr unbestätigte Nachrichten gesendet als erlaubt; aktualisieren oder korrigieren Sie die Client-Bibliothek.
- Die Einstellung wirkt nicht. Sie verbinden sich mit MQTT 3.1.1. Receive Maximum gibt es nur in MQTT 5.
Wie sich gepufferte Nachrichten überhaupt erst anstauen, lesen Sie unter wie MQTT Nachrichten für Offline-Clients puffert. Neu beim Protokoll? Beginnen Sie mit dem MQTT-Tutorial.
Flusskontrolle mit ConnectMQ abstimmen
ConnectMQ betreibt MQTT 3.1.1 und 5.0 über TCP, TLS, WebSocket und sicheren WebSocket, sodass MQTT-5-Properties wie Receive Maximum mit jedem Client funktionieren. Tarifabhängige Kontingente und Flood-Schutz halten einen gemeinsam genutzten MQTT-Broker in der Cloud stabil, während Receive Maximum Ihre einzelnen Geräte schützt. Erstellen Sie einen kostenlosen Serverless-Broker, ohne Kreditkarte, verbinden Sie sich mit YOUR_USERNAME, YOUR_PASSWORD und YOUR_CLIENT_ID und nutzen Sie den MQTT-Client im Browser des Portals, um Testwellen auf Ihre Geräte abzufeuern. Für Produktionsflotten nimmt Ihnen ein verwalteter MQTT-Broker den Broker-Betrieb vollständig ab.
Häufig gestellte Fragen
Was ist der Standardwert von MQTT Receive Maximum?
Wird die Property nicht gesendet, beträgt das Receive Maximum 65.535, was praktisch keinem Limit entspricht. Clients müssen explizit einen kleineren Wert setzen, um Flusskontrolle zu erhalten.
Begrenzt Receive Maximum QoS-0-Nachrichten?
Nein. Es zählt nur QoS-1- und QoS-2-PUBLISH-Pakete, die noch nicht bestätigt wurden. QoS-0-Nachrichten sind in diesem Sinne nie „in flight“.
Gibt es Receive Maximum in MQTT 3.1.1?
Nein. Es ist eine MQTT-5-Property. Clients mit MQTT 3.1.1 verlassen sich auf bibliotheksspezifische In-flight-Einstellungen, die dem Broker nicht mitgeteilt werden.
Was bedeutet der Reason Code 0x93?
Er bedeutet Receive Maximum exceeded: Der Sender hatte mehr unbestätigte QoS-1- oder QoS-2-Nachrichten unterwegs, als der Empfänger erlaubt hat, deshalb hat der Empfänger die Verbindung geschlossen.



