Erst eine korrekte MQTT-TLS-Konfiguration macht aus MQTT, einem Klartextprotokoll, eines, das Sie sicher über das Internet betreiben können. In diesem Leitfaden erfahren Sie, was der Client beim Handshake tatsächlich prüft, welche Einstellungen wichtig sind und wie Sie Python-, Node.js-, ESP32- und Kommandozeilen-Clients für Verbindungen über Port 8883 konfigurieren. Jedes Beispiel verbindet sich mit einem echten Broker, sodass Sie beim Lesen direkt testen können.
Warum MQTT TLS braucht
MQTT selbst hat keine Verschlüsselung. Auf Port 1883 wird das CONNECT-Paket samt Benutzername und Passwort als lesbare Bytes übertragen, ebenso jeder PUBLISH-Payload. Jeder im selben WLAN, ein kompromittierter Router oder ein neugieriger Provider kann diesen Verkehr mitlesen und sogar verändern. In Industrie-4.0-Projekten, in denen Maschinendaten, Rezepturen oder Steuerbefehle zwischen Werk und Cloud fließen, ist das besonders kritisch; Normen wie IEC 62443 behandeln Integrität und Vertraulichkeit der Kommunikation ausdrücklich als Sicherheitsanforderungen. Den größeren Zusammenhang mit Bedrohungen jenseits des Abhörens finden Sie in unserem Überblick zu den Best Practices für MQTT-Sicherheit.
TLS (Transport Layer Security) packt die TCP-Verbindung in einen verschlüsselten, authentifizierten Tunnel, bevor überhaupt MQTT-Bytes ausgetauscht werden. MQTT ändert sich dabei überhaupt nicht; der Broker lauscht einfach auf einem anderen Port, üblicherweise 8883, und der Client führt zuerst einen TLS-Handshake durch. Das bringt Ihnen drei Eigenschaften:
- Vertraulichkeit: Der Verkehr ist verschlüsselt, sodass Zugangsdaten und Payloads bei der Übertragung nicht gelesen werden können.
- Integrität: Manipulierte Pakete werden erkannt und die Verbindung wird getrennt.
- Serverauthentifizierung: Der Client weist nach, dass er mit dem echten Broker spricht und nicht mit einem Betrüger.
Die dritte Eigenschaft wird durch nachlässige Konfiguration am häufigsten ausgehebelt, und sie steht im Mittelpunkt des restlichen Artikels.
Was der Client beim Handshake prüft
Wenn Ihr Client eine TLS-Verbindung öffnet, sendet der Broker sein Zertifikat sowie eventuelle Zwischenzertifikate. Der Client führt dann folgende Prüfungen durch:
- Vertrauenskette: Das Serverzertifikat muss von einem Zwischenzertifikat signiert sein, das wiederum von einer Root-CA signiert ist, der der Client bereits vertraut (sein CA-Store oder eine von Ihnen bereitgestellte CA-Datei).
- Gültigkeitszeitraum: Die aktuelle Zeit muss zwischen den Daten „not before“ und „not after“ des Zertifikats liegen. Deshalb brauchen Geräte ohne Echtzeituhr NTP, bevor sie sich verbinden.
- Hostname-Abgleich: Der Hostname, mit dem Sie sich verbunden haben, muss in der Subject-Alternative-Name-Liste des Zertifikats stehen. Eine Verbindung per IP-Adresse zu einem Zertifikat, das für einen Hostnamen ausgestellt wurde, schlägt fehl, und das ist richtig so.
- Schlüsselbesitz: Der Handshake beweist, dass der Broker den zum Zertifikat passenden privaten Schlüssel besitzt.
Zwei verwandte Details sorgen oft für Stolpersteine. Erstens SNI (Server Name Indication): Der Client sendet den Hostnamen im Handshake mit, damit ein Server mit mehreren Namen das richtige Zertifikat präsentieren kann. Moderne Bibliotheken senden SNI automatisch, wenn Sie einen Hostnamen übergeben. Zweitens ist die Hostname-Prüfung in manchen Bibliotheken von der Kettenprüfung getrennt. Ein Client kann ein völlig gültiges Zertifikat für die falsche Domain akzeptieren, wenn die Hostname-Prüfung deaktiviert ist, und damit wird der Sinn von TLS ausgehebelt.
MQTT-TLS-Einstellungen auf einen Blick
Die folgende Tabelle ordnet die gängigen Transporte Ports und URL-Schemata zu. Die gezeigten Ports werden von ConnectMQ und den meisten Brokern verwendet, die der Konvention folgen.
| Transport | Port | URL-Schema | Verschlüsselt | Typischer Client |
|---|---|---|---|---|
| MQTT über TCP | 1883 | mqtt:// |
Nein | Nur Labortests |
| MQTT über TLS | 8883 | mqtts:// |
Ja | Geräte, Backends, CLI |
| MQTT über WebSocket | 8083 | ws:// |
Nein | Lokale Browsertests |
| MQTT über Secure WebSocket | 8084 | wss:// (Pfad /mqtt) |
Ja | Browser, restriktive Netzwerke |
Für den Vertrauensanker haben Sie drei Optionen:
- System-CA-Store: der Standard für Python, Node.js, Go und die meisten Desktop- oder Server-Clients. Funktioniert, wenn der Broker ein öffentlich vertrauenswürdiges Zertifikat verwendet.
- Explizite CA-Datei: Sie übergeben eine PEM-Datei mit der Root-CA. Erforderlich für private CAs und für die meisten Mikrocontroller.
- Pinning: Sie vertrauen nur einer bestimmten CA oder einem bestimmten Schlüssel. Stärker, aber fragiler; siehe unseren Leitfaden zum ESP32 Certificate Pinning.
Der ConnectMQ-Broker verwendet ein Let's-Encrypt-Zertifikat, dessen Kette zur Root ISRG Root X1 führt, die in jedem gängigen Betriebssystem sowie in den CA-Bundles von Python (über certifi) und Node.js enthalten ist. Auf Desktops und Servern müssen Sie normalerweise überhaupt keine CA-Datei angeben.
Die Verbindung testen, bevor Sie Code schreiben
Bevor Sie Anwendungscode anfassen, prüfen Sie Netzwerkpfad und Zertifikat mit OpenSSL:
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -brief </dev/null
Achten Sie auf Verification: OK und die ausgehandelte Protokollversion. Sehen Sie hier einen Prüffehler, wird auch keine Client-Bibliothek Erfolg haben; unser Artikel zur Behebung von MQTT-TLS-Handshake-Fehlern geht jeden Fehler durch.
Testen Sie dann einen echten MQTT-Roundtrip mit den mosquitto-Clients. Öffnen Sie zwei Terminals und wählen Sie ein eindeutiges Topic-Präfix:
# Terminal 1: über TLS abonnieren, mit dem System-CA-Verzeichnis (Linux/macOS)
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-i tls-sub-7f3a -t "connectmq/demo/7f3a/#" -v
# Terminal 2: über TLS publizieren
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-i tls-pub-7f3a -t "connectmq/demo/7f3a/hello" -m "encrypted hello"
Unter Windows kann mosquitto den System-Store nicht lesen. Laden Sie daher das PEM von ISRG Root X1 bei Let's Encrypt herunter und übergeben Sie es mit --cafile isrgrootx1.pem. Der kostenlose öffentliche MQTT-Broker akzeptiert anonyme Verbindungen, sodass diese Befehle sofort funktionieren. Denken Sie daran, dass der öffentliche MQTT-Broker nur für Tests und Prototypen gedacht und für jeden lesbar ist; senden Sie dort also niemals echte Daten.
Python-Client konfigurieren (paho-mqtt 2.x)
Mit paho-mqtt 2.x lädt tls_set() ohne Argumente die Standard-CA-Zertifikate des Systems, aktiviert die Hostname-Prüfung und verlangt ein gültiges Zertifikat. Genau das wollen Sie.
import ssl
import time
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PORT = 8883
TOPIC = "connectmq/demo/7f3a/python"
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe(TOPIC, qos=1)
def on_message(client, userdata, msg):
print(f"{msg.topic}: {msg.payload.decode()}")
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-tls-7f3a")
client.on_connect = on_connect
client.on_message = on_message
# System-CA-Store, Zertifikat erforderlich, Hostname geprüft,
# neueste TLS-Version, die beide Seiten unterstützen
client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLS_CLIENT)
# Für einen privaten ConnectMQ-Broker die Zugangsdaten aus dem Portal ergänzen:
# client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
time.sleep(1)
client.publish(TOPIC, "hello over TLS", qos=1)
time.sleep(2)
client.loop_stop()
client.disconnect()
Wenn der CA-Store Ihrer Plattform defekt oder veraltet ist, übergeben Sie stattdessen ca_certs=certifi.where(). „Beheben“ Sie einen Fehler niemals mit tls_insecure_set(True); das deaktiviert die Hostname-Prüfung und entfernt stillschweigend die Serverauthentifizierung. Zu den häufigen Python-Fehlern lesen Sie SSL CERTIFICATE_VERIFY_FAILED bei MQTT.
Node.js-Client konfigurieren (MQTT.js v5)
MQTT.js nutzt den eingebauten TLS-Stack von Node, der gegen die mitgelieferte Mozilla-CA-Liste von Node prüft und standardmäßig den Hostnamen verifiziert.
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "node-tls-7f3a",
protocolVersion: 5,
// Für einen privaten Broker:
// username: "YOUR_USERNAME",
// password: "YOUR_PASSWORD",
rejectUnauthorized: true, // Standard; in der Produktion nie auf false setzen
});
const topic = "connectmq/demo/7f3a/node";
client.on("connect", () => {
console.log("Connected over TLS");
client.subscribe(topic, { qos: 1 }, () => {
client.publish(topic, "hello from Node.js", { qos: 1 });
});
});
client.on("message", (t, payload) => {
console.log(`${t}: ${payload.toString()}`);
client.end();
});
client.on("error", (err) => console.error("MQTT error:", err.message));
Wenn Sie einer privaten CA vertrauen müssen, ergänzen Sie ca: fs.readFileSync("ca.pem") in den Optionen. Im Browser verwenden Sie wss://broker.connectmq.com:8084/mqtt; der Browser übernimmt die Zertifikatsprüfung für Sie.
ESP32-Client konfigurieren
Mikrocontroller haben keinen CA-Store eines Betriebssystems, daher betten Sie das Root-Zertifikat ein. Mit dem Arduino-Core sieht WiFiClientSecure plus PubSubClient so aus:
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <time.h>
const char* WIFI_SSID = "your-ssid";
const char* WIFI_PASS = "your-password";
const char* BROKER = "broker.connectmq.com";
// Hier das vollständige PEM von ISRG Root X1 von letsencrypt.org einfügen
static const char ROOT_CA[] = R"EOF(
-----BEGIN CERTIFICATE-----
...ISRG Root X1 certificate body...
-----END CERTIFICATE-----
)EOF";
WiFiClientSecure net;
PubSubClient mqtt(net);
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(250);
// Für die Prüfung der Zertifikatsdaten ist eine gültige Uhrzeit nötig
configTime(0, 0, "pool.ntp.org");
while (time(nullptr) < 1700000000) delay(250);
net.setCACert(ROOT_CA);
mqtt.setServer(BROKER, 8883);
}
void loop() {
if (!mqtt.connected()) {
if (mqtt.connect("esp32-tls-7f3a")) {
mqtt.publish("connectmq/demo/7f3a/esp32", "hello over TLS");
} else {
Serial.printf("MQTT connect failed, state=%d\n", mqtt.state());
delay(5000);
}
}
mqtt.loop();
}
Für einen privaten Broker verwenden Sie mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD"). Das Tutorial ESP32 MQTT über SSL behandelt Speicherverbrauch und Reconnect-Verhalten ausführlicher.
Checkliste für die Produktion
- Verwenden Sie außerhalb des Labors überall Port 8883 (oder 8084 für Browser); deaktivieren oder blockieren Sie unverschlüsselten Port 1883 für Produktions-Clients.
- Prüfen Sie die Zertifikatskette gegen eine vertrauenswürdige Root, statt „alles zu akzeptieren“.
- Lassen Sie die Hostname-Prüfung aktiv und verbinden Sie sich immer per Hostname, nie per IP.
- Synchronisieren Sie auf Embedded-Geräten die Zeit (NTP) vor dem Handshake.
- Vertrauen Sie der Root-CA, nicht dem Leaf-Zertifikat, denn Leaf-Zertifikate werden häufig erneuert.
- Senden Sie Zugangsdaten nur über TLS und speichern Sie sie außerhalb des Quellcodes.
- Planen Sie CA-Wechsel ein: Machen Sie die vertrauenswürdige Root per OTA aktualisierbar.
- Überwachen Sie fehlgeschlagene Verbindungen; wiederholte TLS- oder Authentifizierungsfehler deuten meist auf Fehlkonfiguration oder einen Angriff hin.
Die Serverseite einem verwalteten MQTT-Broker überlassen
Die Broker-Seite von TLS ist die weniger angenehme Hälfte: Zertifikate beschaffen, sie vor dem Ablauf erneuern, Protokollversionen und Cipher auswählen und Listener neu starten, ohne Clients zu verlieren. Ein verwalteter MQTT-Broker nimmt Ihnen diese Arbeit ab. ConnectMQ terminiert TLS auf 8883 und Secure WebSocket auf 8084 mit automatisch erneuerten Let's-Encrypt-Zertifikaten, sodass Ihre Clients nur die oben gezeigte Standardkonfiguration brauchen. Wenn Sie Hosting-Optionen vergleichen, erklärt unser Leitfaden zum Cloud-MQTT-Broker die Abwägungen.
Starten Sie mit ConnectMQ
Erstellen Sie ein kostenloses Konto unter app.connectmq.com, wählen Sie den Plan Serverless (Free) ohne Kreditkarte, legen Sie einen Broker an und kopieren Sie den generierten Benutzernamen, das Passwort und die Client ID. Richten Sie einen der obigen Clients mit diesen Zugangsdaten auf Port 8883 aus, und Sie haben in wenigen Minuten eine verschlüsselte, authentifizierte MQTT-Verbindung.
Häufig gestellte Fragen
Ist MQTT über TLS langsamer als reines MQTT?
Der Handshake fügt beim Verbindungsaufbau Roundtrips und CPU-Aufwand hinzu, aber MQTT-Verbindungen sind langlebig, sodass der Overhead im laufenden Betrieb gering ist. Halten Sie Verbindungen offen und verwenden Sie Sitzungen wieder, statt sich für jede Nachricht neu zu verbinden.
Brauche ich ein Client-Zertifikat, um MQTT über TLS zu nutzen?
Nein. Die meisten Deployments nutzen serverseitiges TLS plus Benutzername und Passwort, die innerhalb des verschlüsselten Tunnels übertragen werden. Client-Zertifikate (Mutual TLS) sind eine zusätzliche Option, die einige selbst gehostete Broker unterstützen.
Welches CA-Zertifikat brauche ich für ConnectMQ?
Das Broker-Zertifikat wird von Let's Encrypt ausgestellt und führt zu ISRG Root X1. Desktop- und Server-Clients vertrauen ihm bereits; Embedded-Geräte sollten dieses Root-PEM einbetten.
Warum schlägt mein Client fehl, wenn ich mich per IP-Adresse verbinde?
Das Zertifikat listet Hostnamen auf, keine IP-Adressen, daher schlägt die Hostname-Prüfung fehl. Verbinden Sie sich immer über broker.connectmq.com oder den Hostnamen Ihres Brokers.



