Python MQTT TLS entscheidet darüber, ob Ihr Benutzername, Ihr Passwort und Ihre Sensordaten im Klartext oder verschlüsselt und authentifiziert durch das Internet reisen. In diesem Tutorial konfigurieren Sie paho-mqtt so, dass es sich mit den vertrauenswürdigen CA-Zertifikaten Ihres Betriebssystems auf Port 8883 verbindet, lassen die Hostnamenprüfung eingeschaltet und beheben die Zertifikatsfehler, an denen die meisten scheitern. Alle Beispiele verbinden sich mit broker.connectmq.com, der ein öffentlich vertrauenswürdiges Let's-Encrypt-Zertifikat ausliefert, sodass keine eigenen CA-Dateien nötig sind.
Was TLS für MQTT leistet
MQTT selbst hat keine Verschlüsselung. Auf Port 1883 läuft alles, einschließlich des CONNECT-Pakets mit Ihren Zugangsdaten, als lesbare Bytes. TLS umhüllt die TCP-Verbindung und gibt Ihnen drei Garantien:
- Vertraulichkeit: Niemand auf dem Netzwerkpfad kann Payloads oder Passwörter lesen.
- Integrität: Niemand kann Nachrichten unterwegs unbemerkt verändern.
- Server-Authentifizierung: Ihr Client prüft, dass er wirklich mit dem angefragten Broker spricht und nicht mit einem Betrüger.
Der dritte Punkt ist derjenige, den man versehentlich deaktiviert. Verschlüsselung ohne Prüfung schützt vor passiven Lauschern, aber nicht vor einem aktiven Angreifer, der sein eigenes Zertifikat präsentiert. In Industrie-4.0-Umgebungen ist das keine Kür: Rahmenwerke wie IEC 62443 und die NIS2-Richtlinie erwarten Schutzmaßnahmen für Vertraulichkeit und Integrität der Kommunikation, auch wenn ein Edge-Gateway nur Maschinendaten aus der Halle sendet. Der Leitfaden zu MQTT-Security-Best-Practices behandelt das Gesamtbild; dieser Artikel konzentriert sich darauf, die Client-Seite richtig aufzusetzen.
ConnectMQ stellt auf jedem Broker diese Ports bereit:
| Port | Transport | Verschlüsselt | Verwendung aus Python |
|---|---|---|---|
| 1883 | MQTT über TCP | Nein | Nur lokale Tests |
| 8883 | MQTT über TLS | Ja | Standard für die Produktion |
| 8083 | MQTT über WebSocket | Nein | Aus Python selten nötig |
| 8084 | MQTT über sicheres WebSocket, Pfad /mqtt |
Ja | Wenn nur Web-Ports erlaubt sind |
Voraussetzungen
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install "paho-mqtt>=2.0"
Prüfen Sie, ob das Zertifikat des Brokers auf Ihrem Rechner validiert wird, bevor Sie Python-Code schreiben. Dieser Befehl zeigt die Kette und das Prüfergebnis:
openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -brief </dev/null
Achten Sie auf Verification: OK. Wenn OpenSSL schon hier scheitert, liegt das Problem am CA-Speicher Ihres Systems oder am Netzwerk, nicht an Ihrem Code.
Der minimale Python-MQTT-TLS-Client
Speichern Sie dies als tls_client.py und ersetzen Sie k7f3q2 durch Ihre eigene zufällige Zeichenfolge:
import ssl
import time
import uuid
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PORT = 8883
TOPIC = "connectmq/demo/k7f3q2/secure"
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"Connect failed: {reason_code}")
return
sock = client.socket()
print(f"Connected over {sock.version()} using {sock.cipher()[0]}")
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=f"tls-{uuid.uuid4().hex[:8]}")
client.on_connect = on_connect
client.on_message = on_message
# Vertrauenswürdige CAs des Betriebssystems nutzen, ein gültiges Zertifikat verlangen
# und prüfen, dass es zu BROKER passt. Das ist der sichere Standard.
client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLS_CLIENT)
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
time.sleep(2)
client.publish(TOPIC, "hello over TLS", qos=1)
time.sleep(2)
client.disconnect()
client.loop_stop()
Führen Sie es aus, und Sie sollten etwas wie Connected over TLSv1.3 using TLS_AES_256_GCM_SHA384 sehen, gefolgt von Ihrer zurückkommenden Nachricht.
Was tls_set() tut
Ohne ca_certs-Argument aufgerufen, erstellt tls_set() einen SSL-Kontext, der die standardmäßig vertrauenswürdigen Zertifikate der Plattform lädt, vom Server ein gültiges Zertifikat verlangt und prüft, ob der Name im Zertifikat zum Host passt, den Sie an connect() übergeben haben. Die expliziten Argumente cert_reqs und tls_version oben sind die Standardwerte, ausgeschrieben, damit die Absicht für den nächsten Leser offensichtlich ist.
Wenn Sie volle Kontrolle bevorzugen, erstellen Sie den Kontext selbst und übergeben ihn:
context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_2
client.tls_set_context(context)
ssl.create_default_context() aktiviert Hostnamen- und Zertifikatsprüfung, und eine Mindestversion lehnt veraltete Protokolle ab. Verwenden Sie entweder tls_set() oder tls_set_context(), nicht beides.
Zugangsdaten für einen privaten Broker hinzufügen
TLS schützt die Zugangsdaten, die Sie senden, kombinieren Sie also immer beides. Mit einem im ConnectMQ-Portal erstellten Broker:
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.connect("broker.connectmq.com", 8883, keepalive=60)
Verwenden Sie den Hostnamen und die Client-ID aus dem Portal; der Broker bindet Client-IDs an die von ihm ausgestellten Zugangsdaten. Laden Sie Geheimnisse aus Umgebungsvariablen (os.environ["MQTT_PASSWORD"]), statt sie in die Versionsverwaltung einzuchecken.
Sicheres WebSocket aus Python
Manche Netzwerke blockieren alles außer den Standard-Web-Ports. paho kann MQTT über sicheres WebSocket auf Port 8084 tunneln, mit derselben TLS-Prüfung:
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id=f"wss-{uuid.uuid4().hex[:8]}",
transport="websockets",
)
client.ws_set_options(path="/mqtt")
client.tls_set()
client.connect("broker.connectmq.com", 8084, keepalive=60)
Alles andere, also Callbacks, Abonnements und Publishing, bleibt gleich. Der Artikel MQTT über WebSocket erklärt, wann dieser Transport sinnvoll ist.
Häufige TLS-Fehler beheben
Die meisten TLS-Fehler haben eine Handvoll Ursachen. Ordnen Sie Ihre Fehlermeldung dieser Tabelle zu:
| Fehler | Wahrscheinliche Ursache | Lösung |
|---|---|---|
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate |
Python findet keine vertrauenswürdigen CAs | Siehe die Lösungen zum CA-Speicher unten |
Hostname mismatch, certificate is not valid for '...' |
Verbindung per IP-Adresse oder Alias | Mit dem exakten Hostnamen des Brokers verbinden |
certificate is not yet valid oder certificate has expired |
Die Uhr des Geräts geht falsch | Zeit vor dem Verbinden per NTP synchronisieren |
WRONG_VERSION_NUMBER |
TLS-Client spricht mit dem unverschlüsselten Port 1883 | Port 8883 verwenden |
| Verbindung hängt und läuft dann in einen Timeout | Unverschlüsselter Client spricht mit TLS-Port 8883, oder Port blockiert | tls_set() aufrufen oder Port 8084 versuchen |
Einen fehlenden CA-Speicher beheben
- macOS mit Python von python.org: Diese Python-Version hat keinen Zugriff auf den System-Schlüsselbund. Führen Sie das Skript "Install Certificates.command" im Python-Anwendungsordner aus oder verweisen Sie paho auf certifi:
pip install certifi, dannclient.tls_set(ca_certs=certifi.where()). - Schlanke Docker-Images: Installieren Sie das CA-Bundle, zum Beispiel
apt-get install -y ca-certificatesbei Debian-basierten Images. - Unternehmens- und Werksnetze mit TLS-Inspektion: Ein Proxy ersetzt Zertifikate womöglich durch eigene. Fragen Sie die IT nach der Root-CA des Unternehmens und übergeben Sie sie mit
ca_certs=, statt die Prüfung zu deaktivieren. - Embedded Linux: Aktualisieren Sie das CA-Bundle; sehr alte Images enthalten möglicherweise nicht das ISRG-Root-X1-Zertifikat, auf das Let's Encrypt verweist.
TLS niemals durch Abschalten der Prüfung "reparieren"
Sie werden auf Ratschläge stoßen, client.tls_insecure_set(True) aufzurufen oder cert_reqs=ssl.CERT_NONE zu übergeben. Beides lässt den Fehler verschwinden, indem jedes Zertifikat von jedem akzeptiert wird, was die Server-Authentifizierung stillschweigend entfernt. Nutzen Sie das nur für eine schnelle Diagnose in Ihrem eigenen Labornetz, niemals in ausgeliefertem Code.
Vermeiden Sie außerdem, das Leaf-Zertifikat des Brokers in Ihrem Client zu pinnen. Let's-Encrypt-Zertifikate werden regelmäßig erneuert, ein gepinntes Zertifikat bricht also bei der nächsten Erneuerung. Vertrauen Sie stattdessen der CA, genau das tut der Standardspeicher.
Checkliste für die Produktion
Bevor Sie einen Python-Client mit TLS ausrollen, bestätigen Sie jeden Punkt:
- Überall wird Port 8883 (oder 8084 mit WebSocket) verwendet; nichts fällt auf 1883 zurück.
tls_set()odertls_set_context()wird ohnetls_insecure_set(True)aufgerufen.- Der Client verbindet sich per Hostname, niemals per IP-Adresse.
- Das Gerät hat eine genaue Uhrzeit, beim Booten per NTP synchronisiert.
- Das CA-Bundle auf dem Gerät wird gepflegt und mit dem Betriebssystem aktualisiert.
- Zugangsdaten stammen aus Umgebungsvariablen oder einem Secrets-Store.
- Eine Reconnect-Logik ist vorhanden; der Leitfaden zu paho-mqtt-Reconnects zeigt ein robustes Muster.
Wie es weitergeht
Wenn Sie neu bei paho sind, behandelt das paho-mqtt-Python-Tutorial die Grundlagen von Publish und Subscribe, und der Leitfaden zu aiomqtt und asyncio zeigt, wie Sie einem asynchronen Client einen tls_context übergeben. Für Clients in anderen Sprachen vergleicht die Übersicht der MQTT-Client-Bibliotheken die TLS-Unterstützung in verschiedenen Ökosystemen. Die Dokumentation des Python-ssl-Moduls ist die Referenz für jede hier verwendete Kontextoption.
Sichern Sie Ihren MQTT-Verkehr mit ConnectMQ
ConnectMQ ist ein verwalteter MQTT-Broker mit TLS auf 8883 und sicherem WebSocket auf 8084, standardmäßig aktiviert und gestützt auf ein automatisch verwaltetes Let's-Encrypt-Zertifikat, sodass Ihre Python-Clients den Broker mit dem CA-Speicher prüfen, den sie bereits haben. Testen Sie auf dem öffentlichen MQTT-Broker, der für Tests und Prototypen gedacht ist, und wechseln Sie dann zu einem privaten Cloud-MQTT-Broker mit generierten Zugangsdaten. Erstellen Sie Ihren kostenlosen Broker im Serverless-Plan, ohne Kreditkarte.
Häufig gestellte Fragen
Muss ich ein CA-Zertifikat herunterladen, um mich per TLS zu verbinden?
Nein. Der Broker nutzt ein Let's-Encrypt-Zertifikat, dessen Kette zu einer Root führt, der aktuelle Betriebssysteme vertrauen, daher funktioniert tls_set() mit dem Standard-CA-Speicher.
Welchen Port verwendet MQTT über TLS?
Der Standardport ist 8883. ConnectMQ bietet zusätzlich MQTT über sicheres WebSocket auf Port 8084 mit dem Pfad /mqtt.
Warum schlägt Python MQTT TLS fehl, wenn ich mich per IP-Adresse verbinde?
Die Hostnamenprüfung vergleicht den Namen im Zertifikat mit dem Host, mit dem Sie sich verbunden haben. Eine IP-Adresse passt nicht zum Namen des Brokers, die Prüfung schlägt also absichtlich fehl; verwenden Sie den Hostnamen.
Reicht TLS aus, um meinen MQTT-Client abzusichern?
TLS schützt die Verbindung, Sie benötigen aber dennoch starke, gerätespezifische Zugangsdaten und ein durchdachtes Topic-Design. Kombinieren Sie TLS mit eindeutigen Zugangsdaten aus dem Broker-Portal.



