Um eine MQTT-TLS-Verbindung zu testen, prüfst du drei Ebenen nacheinander: zuerst den TLS-Handshake selbst mit openssl s_client, dann eine echte MQTT-Sitzung mit mosquitto_sub oder mosquitto_pub und schließlich die Client-Bibliothek, die deine Geräte verwenden. Jede Ebene kann aus anderen Gründen scheitern — getrennt getestet weißt du genau, welche kaputt ist.
Alle Beispiele nutzen broker.connectmq.com auf Port 8883 (MQTT über TLS). Ersetze den Host durch deinen eigenen Broker.
Schritt 1: Handshake mit openssl prüfen
openssl s_client spricht TLS, aber kein MQTT — genau das willst du: Es zeigt das Zertifikat, das der Broker sendet, und ob dein Rechner ihm vertraut, ohne dass eine MQTT-Bibliothek dazwischenfunkt.
openssl s_client -connect broker.connectmq.com:8883 \
-servername broker.connectmq.com \
-verify_hostname broker.connectmq.com \
-showcerts </dev/nullWas die Optionen bewirken:
-servernamesendet SNI (Server Name Indication). Broker und Load Balancer mit mehreren Namen wählen darüber das Zertifikat aus. Ohne SNI bekommst du eventuell ein Standardzertifikat und einen Hostname-Fehler.-verify_hostnamelässt openssl prüfen, ob das Zertifikat für diesen Namen gilt — dieselbe Prüfung, die dein MQTT-Client macht.-showcertsgibt jedes Zertifikat aus, das der Server sendet, damit du siehst, ob das Intermediate dabei ist.</dev/nullbeendet die Verbindung direkt nach dem Handshake, statt auf Eingaben zu warten.
Am Ende der Ausgabe suchst du nach:
Verify return code: 0 (ok)Alles andere ist ein Problem, das du auch im MQTT-Client sehen wirst:
| openssl-Ergebnis | Bedeutung |
|---|---|
Verify return code: 20 (unable to get local issuer certificate) | Die CA (oder ein fehlendes Intermediate) ist nicht in deinem Trust Store |
Verify return code: 18 (self-signed certificate) | Das Serverzertifikat ist selbst signiert; übergib die CA mit -CAfile |
Verify return code: 19 (self-signed certificate in certificate chain) | Die Kette endet in einer privaten Root, der du nicht vertraust |
Verify return code: 10 (certificate has expired) | Zertifikat auf dem Broker erneuern |
Verify return code: 62 (hostname mismatch) | Das Zertifikat enthält den verwendeten Namen nicht |
wrong version number | Der Port spricht unverschlüsseltes MQTT, kein TLS (oft 1883) |
connect: Connection refused / Timeout | Port geschlossen oder gefiltert — kein TLS-Problem |
Bei einem Broker mit privater CA fügst du -CAfile ca.crt hinzu und wiederholst den Befehl. Liefert er dann 0 (ok), sind deine Zertifikate in Ordnung und der Client braucht nur dieselbe CA-Datei.
Zertifikat schnell untersuchen
openssl s_client -connect broker.connectmq.com:8883 \
-servername broker.connectmq.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNamePrüfe, dass subjectAltName genau den Hostnamen enthält, den deine Geräte verwenden. Moderne Clients ignorieren den Common Name des Zertifikats; ein Name, der nur im CN steht, zählt also nicht. Für einen CI-Check, der zwei Wochen vor Ablauf fehlschlägt, leitest du das Zertifikat in openssl x509 -noout -checkend 1209600.
Um zu testen, welche TLS-Versionen der Broker akzeptiert, wiederhole den ersten Befehl mit -tls1_2 oder -tls1_3. Ein Gerät mit altem TLS-Stack, das nur TLS 1.2 spricht, braucht einen Broker, der 1.2 weiterhin anbietet — siehe TLS 1.2 vs. 1.3 bei MQTT.
Schritt 2: Echte MQTT-Sitzung über TLS
Ein erfolgreicher Handshake beweist noch nicht, dass der MQTT-Listener dahinter funktioniert. Abonniere und publishe über 8883:
mosquitto_sub -h broker.connectmq.com -p 8883 \
--cafile /etc/ssl/certs/ca-certificates.crt \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-t testmqtt/tls/check -v -dmosquitto_pub -h broker.connectmq.com -p 8883 \
--cafile /etc/ssl/certs/ca-certificates.crt \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-t testmqtt/tls/check -m "hello over tls"Die mosquitto-Clients aktivieren TLS nur, wenn du eine CA-Option angibst. Nutze --cafile mit deinem CA-Bundle (der Pfad oben gilt für Debian/Ubuntu; unter macOS mit Homebrew liegt es unter $(brew --prefix)/etc/ca-certificates/cert.pem), --capath /etc/ssl/certs oder --tls-use-os-certs ab mosquitto 2.x. Bei einer privaten CA zeigt --cafile auf deine ca.crt. Für Mutual TLS ergänzt du --cert client.crt --key client.key — siehe Client-Zertifikate und mTLS.
Schlägt es fehl, ist mosquitto wortkarg: Es gibt Error: A TLS error occurred. aus und sonst nichts. Geh zurück zu Schritt 1 — openssl sagt dir, warum. Funktioniert openssl, aber mosquitto nicht, vergleiche den Hostnamen: -h muss der Name im Zertifikat sein, keine IP-Adresse.
Schritt 3: Aus deinem Client-Code testen
Zum Schluss testest du mit der Bibliothek, die deine Anwendung nutzt. Zertifikatsspeicher und Standardwerte unterscheiden sich je nach Sprache — eine Verbindung, die mit mosquitto klappt, kann hier trotzdem scheitern.
import os
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
print("CONNACK:", reason_code)
client.publish("testmqtt/tls/check", "hello from python over tls", qos=1)
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5)
c.tls_set() # System-CAs, Hostname-Prüfung aktiv; ca_certs="ca.crt" für eine private CA
c.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
c.on_connect = on_connect
c.connect("broker.connectmq.com", 8883)
c.loop_forever()import mqtt from "mqtt";
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
username: process.env.MQTT_USER,
password: process.env.MQTT_PASS,
// ca: fs.readFileSync("ca.crt"), // nur für eine private CA
reconnectPeriod: 0,
});
client.on("connect", () => {
console.log("connected over TLS");
client.publish("testmqtt/tls/check", "hello from node over tls", () => client.end());
});
client.on("error", (err) => console.error(err.code, err.message));Die Fehler, die dabei entstehen, sind genau die, nach denen gesucht wird:
| Bibliothek | Fehler | Häufige Ursache |
|---|---|---|
| Python | [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate | CA oder Intermediate fehlt |
| Python | certificate verify failed: Hostname mismatch, certificate is not valid for '...' | Verbindung per IP oder mit falschem Namen |
| Python | [SSL: WRONG_VERSION_NUMBER] wrong version number | TLS-Client an einem unverschlüsselten Port |
| Node.js | UNABLE_TO_VERIFY_LEAF_SIGNATURE — unable to verify the first certificate | Server sendet das Intermediate nicht |
| Node.js | SELF_SIGNED_CERT_IN_CHAIN | Private CA nicht in ca übergeben |
| Node.js | ERR_TLS_CERT_ALTNAME_INVALID — Hostname/IP does not match certificate's altnames | Name nicht in der SAN-Liste |
Die Lösungen findest du einzeln in certificate verify failed, TLS-Handshake fehlgeschlagen und Hostname mismatch. Der Code-Generator erzeugt TLS-fähige Verbindungs-Snippets für weitere Sprachen.
Kurze TLS-Test-Checkliste
openssl s_clientmit-servernameund-verify_hostnameliefertVerify return code: 0 (ok).-showcertszeigt das Serverzertifikat und das Intermediate.- Das SAN enthält genau den Hostnamen der Clients; das Zertifikat läuft nicht bald ab.
mosquitto_subundmosquitto_pubtauschen auf8883mit aktiver Prüfung eine Nachricht aus.- Die Bibliothek deiner Anwendung verbindet sich mit ihrem Standard-Trust-Store (oder mit der privaten CA, die du mitlieferst).
- Der unverschlüsselte Port
1883ist in der Produktion geschlossen oder deaktiviert, wenn TLS Pflicht ist. - Geräte mit älteren TLS-Stacks verbinden sich mit der TLS-Version und den Cipher Suites, die du erlaubst.
Du willst zusätzlich einen Check im Browser? Der Online-MQTT-Client verbindet sich über sichere WebSockets auf 8084, die in vielen Setups dasselbe Zertifikat nutzen — ein schneller Weg, die TLS-Seite des Brokers zu bestätigen, bevor du ein Gerät debuggst.
Wer TLS Ebene für Ebene testet, macht aus einem vagen „TLS-Fehler“ in wenigen Minuten eine konkrete Ursache. Behalte den openssl-Befehl und den Ablauf-Check in deinen Skripten und führe sie aus, sobald ein Zertifikat erneuert wird oder sich ein Load Balancer ändert.
Häufig gestellte Fragen
Wie prüfe ich, ob ein MQTT-Broker TLS unterstützt?
Führe openssl s_client -connect host:8883 -servername host aus. Klappt der Handshake, siehst du die Zertifikatskette und 'Verify return code: 0 (ok)'. Ein Fehler 'wrong version number' bedeutet, dass der Port unverschlüsseltes MQTT spricht, kein TLS.
Warum funktioniert TLS im Browser, aber nicht auf meinem Gerät?
Meist sendet der Server sein Intermediate-Zertifikat nicht mit. Browser können fehlende Intermediates selbst nachladen; openssl, mosquitto und Embedded-TLS-Stacks können das nicht. Prüfe, ob s_client -showcerts das Intermediate anzeigt, und korrigiere die Zertifikatsdatei des Brokers.
Ist --insecure oder tls_insecure_set(True) sicher?
Nur als vorübergehende Diagnose auf deinem eigenen Rechner. Diese Optionen schalten die Hostname-Prüfung ab und machen die Verbindung anfällig für Man-in-the-Middle-Angriffe. Korrigiere stattdessen das Zertifikat oder den Hostnamen und lass die Prüfung aktiv.
