Broker-Tests

Große MQTT-Payloads und die maximale Nachrichtengröße testen

Wie groß darf eine MQTT-Nachricht sein? Das 256-MB-Limit, Broker-Limits wie message_size_limit, MQTT 5 Maximum Packet Size und wie du die Grenze testest.

Aktualisiert · 9 Min. Lesezeit

Große MQTT-Payloads und die maximale Nachrichtengröße testen

Die maximale MQTT-Nachrichtengröße liegt laut Protokoll bei 268.435.455 Bytes, also rund 256 MB. In der Praxis kommst du nie so weit: Broker, Cloud-Dienste und Client-Bibliotheken setzen niedrigere Limits, und manche verwerfen zu große Nachrichten, ohne dir Bescheid zu geben. Dieser Guide zeigt, wo welches Limit sitzt, wie MQTT 5 es sichtbar macht und wie du die echte Obergrenze deines Brokers testest, bevor ein Firmware-Image oder ein Kamera-Snapshot sie für dich findet.

Woher das 256-MB-Limit kommt

Jedes MQTT Control Packet beginnt mit einem Fixed Header, der die Remaining Length enthält: die Anzahl der folgenden Bytes. Sie wird als Integer variabler Länge mit höchstens vier Bytes zu je sieben Nutzbits kodiert. Der größte Wert ist also 2^28 − 1 = 268.435.455.

Diese Zahl umfasst den gesamten Rest des Pakets, nicht nur deine Daten. Ein PUBLISH enthält außerdem:

  • den Topic-Namen (2 Byte Länge + UTF-8-Bytes),
  • einen 2 Byte langen Packet Identifier bei QoS 1 und 2,
  • bei MQTT 5 einen Properties-Block (Content Type, User Properties, Message Expiry …).

Die größtmögliche Payload liegt also knapp unter 256 MB und schrumpft mit langen Topics und vielen User Properties. Der MQTT-Paketgrößen-Rechner zeigt den genauen Overhead für Topic, QoS und Payload.

Die Limits, an die du wirklich stößt

EbeneWo das Limit gesetzt wirdTypisches Verhalten bei Überschreitung
ProtokollRemaining Length (4 Bytes)Paket lässt sich gar nicht kodieren
Mosquittomax_packet_size, früher message_size_limitMQTT 5: Disconnect mit 0x95; 3.1.1: Nachricht verworfen oder Verbindung geschlossen
EMQXmqtt.max_packet_size (Standard 1 MB)Verbindung geschlossen, Fehler im Broker-Log
HiveMQmax-packet-size in der MQTT-KonfigurationMQTT-5-Clients erhalten 0x95; 3.1.1-Clients werden getrennt
Cloud-IoT-DiensteService-QuotasAWS IoT Core begrenzt Payloads auf 128 KB, Azure IoT Hub Device-to-Cloud-Nachrichten auf 256 KB – prüfe die aktuellen Quota-Seiten
Client-BibliothekInterne Puffer, MQTT 5 Maximum Packet SizeFehler beim Publish oder stilles Verwerfen beim Empfang
NetzwerkpfadProxys, Load Balancer, WebSocket-GatewaysTimeouts oder Resets auf langsamen Leitungen

Standardwerte ändern sich zwischen Versionen. Nutze die Tabelle deshalb als Karte, wo du nachsehen musst, nicht als Liste garantierter Zahlen. Lies die Konfigurationsreferenz genau der Version, die du betreibst.

Mosquitto-Konfiguration

Mosquitto 2.x hat zwei verwandte Optionen:

mosquitto.conf
# Maximum size of any MQTT packet the broker accepts, in bytes.
# MQTT 5 clients are told this value in CONNACK.
max_packet_size 1048576

# Older option: maximum PUBLISH payload size. Deprecated in favour of
# max_packet_size, but still found in many existing configs.
# message_size_limit 1048576

Ist keine der beiden gesetzt, gilt bei Mosquitto kein niedrigeres Limit als das des Protokolls – ein einzelner Client kann den Broker also dazu bringen, Hunderte Megabyte zu allokieren. Ein explizites Limit gehört zu einer vernünftigen Produktionskonfiguration; der mosquitto.conf-Generator setzt es mit.

MQTT 5 Maximum Packet Size

MQTT 3.1.1 kennt keine Größenaushandlung. MQTT 5 führt die Property Maximum Packet Size in beide Richtungen ein:

  • CONNECT → Broker: Der Client teilt mit, welches Paket er maximal empfangen will. Der Broker darf nichts Größeres senden; ist eine passende Nachricht für diesen Subscriber zu groß, verwirft der Broker sie nur für diesen Client.
  • CONNACK → Client: Der Broker teilt mit, welches Paket er maximal akzeptiert. Eine saubere Client-Bibliothek weigert sich, größere Pakete zu senden. Wird trotzdem eines gesendet, trennt der Broker die Verbindung mit Reason Code 0x95 Packet too large.

Der zweite Fall ist der Fehler, nach dem Leute suchen. Seine Bedeutung und verwandte Codes findest du in der Referenz der MQTT Reason Codes; ausführlich erklärt ist er in MQTT packet too large.

Schnelltest mit mosquitto_pub

Erzeuge Dateien bekannter Größe und schicke sie durch den Broker. -f sendet eine Datei als Payload; -N verhindert, dass mosquitto_sub einen Zeilenumbruch anhängt, damit die Byte-Zahl exakt bleibt.

large-payload-cli.sh
HOST=broker.connectmq.com
TOPIC="testmqtt/payload-$RANDOM/blob"

for size in 64K 512K 1M 4M; do
  head -c "$size" /dev/urandom > "/tmp/blob-$size"
done

# Terminal 1: eine Nachricht empfangen und die Bytes zählen
mosquitto_sub -h "$HOST" -t "$TOPIC" -V mqttv5 -C 1 -W 30 -N | wc -c

# Terminal 2: jeweils eine Größe senden
mosquitto_pub -h "$HOST" -t "$TOPIC" -V mqttv5 -q 1 -f /tmp/blob-1M -d

-d gibt jedes gesendete und empfangene Paket aus. So siehst du, ob das PUBLISH den Client verlassen hat und ob die Verbindung direkt danach geschlossen wurde. Gibt wc -c die Dateigröße aus, ist die Nachricht angekommen; läuft mosquitto_sub nach 30 Sekunden in den Timeout, nicht. Um einen eingeschränkten Subscriber zu simulieren, ergänze -D connect maximum-packet-size 65536 bei mosquitto_sub – größere Nachrichten verschwinden dann nur für diesen Client.

Automatischer Größen-Sweep in Python

Für ein reproduzierbares Ergebnis veröffentlicht dieses paho-mqtt-2.x-Skript Payloads wachsender Größe mit QoS 1, prüft jede per SHA-256-Hash und stoppt beim ersten Fehler. Außerdem zeigt es das vom Broker angekündigte Limit.

payload_sweep.py
import hashlib, os, threading, time, uuid
import paho.mqtt.client as mqtt

HOST, PORT = "broker.connectmq.com", 1883
TOPIC = f"testmqtt/payload-{uuid.uuid4().hex[:8]}/blob"
SIZES = [1_024, 65_536, 262_144, 1_048_576, 4_194_304, 16_777_216]
TIMEOUT = 30
result, got = {}, threading.Event()

def on_connect(client, userdata, flags, reason_code, properties):
    limit = getattr(properties, "MaximumPacketSize", None)
    print(f"connected: {reason_code}, broker max packet = {limit or 'not advertised'}")

def on_disconnect(client, userdata, flags, reason_code, properties):
    print(f"disconnected: {reason_code}")

def on_message(client, userdata, msg):
    result["digest"] = hashlib.sha256(msg.payload).hexdigest()
    got.set()

def make_client(name):
    c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                    client_id=f"{name}-{uuid.uuid4().hex[:6]}", protocol=mqtt.MQTTv5)
    # c.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
    c.on_connect, c.on_disconnect, c.on_message = on_connect, on_disconnect, on_message
    c.connect(HOST, PORT)
    c.loop_start()
    return c

sub = make_client("sweep-sub")
sub.subscribe(TOPIC, qos=1)
pub = make_client("sweep-pub")
time.sleep(2)

for size in SIZES:
    payload = os.urandom(size)
    got.clear()
    start = time.perf_counter()
    info = pub.publish(TOPIC, payload, qos=1)
    if info.rc != mqtt.MQTT_ERR_SUCCESS:
        print(f"{size:>10} B  FAIL  publish rc={info.rc}")
        break
    if not got.wait(TIMEOUT):
        print(f"{size:>10} B  FAIL  not delivered within {TIMEOUT}s")
        break
    ok = result["digest"] == hashlib.sha256(payload).hexdigest()
    print(f"{size:>10} B  {'OK  ' if ok else 'BAD '}  {(time.perf_counter() - start) * 1000:.0f} ms")

pub.loop_stop(); sub.loop_stop()

Typische Ausgaben und ihre Bedeutung:

  • Alle Größen OK – der Broker akzeptiert mindestens 16 MB. Entscheide, ob du das überhaupt willst.
  • Zugestellt bis N, dann „not delivered“, kein Disconnect – der Broker verwirft zu große Nachrichten stillschweigend, oder das Limit des Subscribers selbst greift.
  • „disconnected: Packet too large“ – ein MQTT-5-Broker setzt max_packet_size durch. Die letzte erfolgreiche Größe ist deine praktische Obergrenze.
  • Latenz steigt stark mit der Größe – du misst Bandbreite, nicht den Broker. Vergleiche die Werte mit deiner Upload-Geschwindigkeit.

Führe den Sweep einmal über TCP und einmal über WebSockets aus (Port 8083 oder 8084 mit Pfad /mqtt): Proxys vor WebSocket-Listenern haben manchmal eigene Frame- oder Puffer-Limits. Einzelne Payloads kannst du auch interaktiv im Online-MQTT-Client ausprobieren.

Große Payloads haben Nebenwirkungen

Selbst wenn der Broker eine 10-MB-Nachricht akzeptiert, ist sie nicht umsonst:

  • Head-of-Line-Blocking. MQTT läuft über eine einzige TCP-Verbindung. Während ein großes PUBLISH übertragen wird, bewegt sich auf dieser Verbindung nichts anderes – auch keine kleinen, dringenden Befehle und keine PINGREQ-Pakete. Auf einer langsamen Mobilfunkverbindung kann das Keep-Alive-Timeouts auslösen.
  • Speicher. Der Broker hält die komplette Nachricht meist im Speicher, und zwar einmal pro wartendem Subscriber mit offline persistenter Session. Große Retained Messages bleiben dort dauerhaft.
  • Wiederholungen. Bei QoS 1 oder 2 bedeutet ein Verbindungsabbruch, dass das ganze Paket erneut gesendet wird – ein Fortsetzen gibt es nicht.
  • Fan-out. Eine 5-MB-Nachricht an 200 Subscriber ergibt 1 GB ausgehenden Traffic. Die Rechnung findest du in MQTT-Bandbreiten-Overhead.

Design-Muster für große Daten

  1. Nachrichten standardmäßig klein halten. Telemetrie, Events und Befehle sollten Bytes oder Kilobytes groß sein. Binäre Formate wie CBOR oder Protobuf verkleinern JSON-Payloads deutlich.
  2. Große Dateien chunken. In nummerierte Teile (zum Beispiel je 64 KB) auf …/file/<id>/<n> aufteilen, ein Manifest mit Gesamtgröße und Hash senden und beim Empfänger wieder zusammensetzen. Dateiübertragung über MQTT zeigt eine vollständige Implementierung.
  3. Einen Zeiger senden, nicht die Datei. Per HTTP in einen Object Storage hochladen und URL samt Metadaten über MQTT veröffentlichen. Das ist die übliche Wahl für Kamerabilder und Firmware.
  4. Ein explizites Limit am Broker setzen, etwas über deiner größten legitimen Nachricht, damit ein fehlerhafter Client den Speicher nicht aufbrauchen kann.

Test-Payload im Browser veröffentlichen

Die 256-MB-Grenze des Protokolls ist eine theoretische Zahl; entscheidend ist das kleinste Limit auf deinem Pfad, vom Client-Puffer über die Broker-Konfiguration bis zur Cloud-Quota. Miss es mit einem Größen-Sweep, mach es in der Broker-Konfiguration explizit und plane alles Größere als Chunks oder Zeiger statt als einzelne Nachricht.

Häufig gestellte Fragen

Wie groß darf eine MQTT-Nachricht maximal sein?

Das Protokoll erlaubt Control Packets bis 268.435.455 Bytes (etwa 256 MB), weil das Feld Remaining Length höchstens vier Bytes lang ist. Die nutzbare Payload ist etwas kleiner, und fast jeder Broker oder Cloud-Dienst setzt ein deutlich niedrigeres Limit.

Warum verschwindet meine große MQTT-Nachricht ohne Fehlermeldung?

Mit MQTT 3.1.1 kann ein Broker ein einzelnes PUBLISH nicht mit Begründung ablehnen. Viele Broker verwerfen zu große Nachrichten daher stillschweigend oder schließen die Verbindung. Nutze MQTT 5, lies die Maximum Packet Size aus dem CONNACK und achte auf den Reason Code 0x95 Packet too large.

Sollte ich Dateien oder Bilder über MQTT senden?

Kleine Dateien von einigen hundert Kilobyte sind auf den meisten Brokern kein Problem. Größere Dateien teilst du besser in nummerierte Chunks oder veröffentlichst eine URL zu einem Object Storage, damit eine riesige Nachricht weder die Verbindung blockiert noch den Speicher des Brokers aufbraucht.