MQTT-Sicherheit

SSL Certificate Verify Failed bei MQTT: Python-Clients richtig reparieren

Sie erhalten „[SSL: CERTIFICATE_VERIFY_FAILED]“, wenn sich Ihr Python-MQTT-Client auf Port 8883 verbindet? So finden Sie die genaue Ursache und beheben sie auf jeder Plattform richtig, ohne die Prüfung zu deaktivieren.

Illustration zum Fehler SSL Certificate Verify Failed bei MQTT mit einem Python-Terminal, das eine abgelehnte Zertifikatskette auf Port 8883 zeigt
Probieren Sie es auf Ihrem eigenen MQTT-Broker ausHolen Sie sich im Free-Tarif einen privaten, verwalteten MQTT-Broker und starten Sie mit fertigen Codebeispielen.
Kostenlos testen Codebeispiele Keine Kreditkarte erforderlich

Der MQTT-Fehler „ssl certificate verify failed“ bedeutet, dass Python das Zertifikat des Brokers während des TLS-Handshakes abgelehnt hat. Das ist eine Sicherheitsfunktion, die ihre Arbeit macht, und die Lösung besteht fast nie darin, sie abzuschalten. Dieser Leitfaden zeigt, wie Sie den genauen Grund aus der Fehlermeldung ablesen und ihn mit paho-mqtt unter Windows, macOS, Linux und Docker korrekt beheben. Als bekanntermaßen funktionierende Referenz dient broker.connectmq.com auf Port 8883.

Die Fehlermeldung lesen

Die vollständige Exception sieht meist so aus:

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
unable to get local issuer certificate (_ssl.c:1000)

Entscheidend ist der Teil nach dem Doppelpunkt. Die drei häufigen Varianten deuten auf unterschiedliche Ursachen hin:

Detail der Meldung Bedeutung Wahrscheinlichste Lösung
unable to get local issuer certificate Python findet die Root-CA nicht, die die Kette signiert hat CA-Bundle reparieren oder bereitstellen
self-signed certificate in certificate chain Etwas hat ein Zertifikat präsentiert, das von einer nicht vertrauenswürdigen privaten CA signiert ist Inspektion durch Proxy oder Virenscanner oder eine nicht konfigurierte private Broker-CA
Hostname mismatch, certificate is not valid for '...' Der Name, mit dem Sie sich verbunden haben, steht nicht im Zertifikat Mit dem korrekten Hostnamen verbinden, nicht mit einer IP
certificate has expired Uhr falsch oder Serverzertifikat abgelaufen Systemzeit korrigieren oder Serverzertifikat erneuern

Schritt 1: Prüfen, ob Python den Broker verifizieren kann

Dieses kurze Skript testet TLS ohne MQTT, genau mit den Einstellungen, die paho-mqtt standardmäßig verwendet:

import socket
import ssl

HOST, PORT = "broker.connectmq.com", 8883

ctx = ssl.create_default_context()
print("OpenSSL:", ssl.OPENSSL_VERSION)
print("Default verify paths:", ssl.get_default_verify_paths())

with socket.create_connection((HOST, PORT), timeout=10) as sock:
    with ctx.wrap_socket(sock, server_hostname=HOST) as tls:
        cert = tls.getpeercert()
        print("Connected with", tls.version())
        print("Issuer:", dict(x[0] for x in cert["issuer"]))
        print("Valid until:", cert["notAfter"])

Scheitert dieses Skript mit demselben Fehler, liegt das Problem beim Trust Store der Python-Umgebung, bei der Uhr oder beim Netzwerk. Gelingt es, aber Ihr MQTT-Code scheitert, liegt das Problem in der Konfiguration des MQTT-Clients: ein falscher ca_certs-Pfad, eine Verbindung per IP oder ein Broker mit privatem Zertifikat.

Schritt 2: Ein korrektes TLS-Setup für paho-mqtt verwenden

Mit paho-mqtt 2.x ist dies die Basis, die mit jedem Broker mit öffentlich vertrauenswürdigem Zertifikat funktioniert, auch mit ConnectMQ:

import ssl
import time
import certifi
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
TOPIC = "connectmq/demo/a8d2/verify-test"

def on_connect(client, userdata, flags, reason_code, properties):
    print("CONNACK:", reason_code)
    client.subscribe(TOPIC)
    client.publish(TOPIC, "certificate verified")

def on_message(client, userdata, msg):
    print("Received:", msg.payload.decode())

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-verify-a8d2")
client.on_connect = on_connect
client.on_message = on_message

# certifi liefert das CA-Bundle von Mozilla, unabhängig vom Store des Betriebssystems
client.tls_set(ca_certs=certifi.where(), cert_reqs=ssl.CERT_REQUIRED)

# Privater ConnectMQ-Broker:
# client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")

client.connect(BROKER, 8883, keepalive=60)
client.loop_start()
time.sleep(3)
client.loop_stop()
client.disconnect()

Installieren Sie die Abhängigkeiten mit pip install "paho-mqtt>=2.0" certifi. Die Übergabe von certifi.where() sorgt für identisches Verhalten auf jedem Betriebssystem und ist oft die schnellste dauerhafte Lösung. Halten Sie certifi aktuell, denn CA-Listen ändern sich im Laufe der Zeit.

Lösungen für jede Plattform

macOS

Python-Installer von python.org bringen ihr eigenes OpenSSL mit und nutzen nicht die macOS-Schlüsselbundverwaltung. Bis Sie das mitgelieferte Skript ausführen, haben sie überhaupt keine CA-Zertifikate, was zu unable to get local issuer certificate führt. Beheben Sie das, indem Sie das Zertifikatsskript des Installers ausführen:

/Applications/Python\ 3.12/Install\ Certificates.command

Passen Sie die Versionsnummer an Ihre Installation an. Homebrew-Python nutzt das CA-Bundle von Homebrew und funktioniert meist sofort; falls nicht, führen Sie brew reinstall ca-certificates aus. Die explizite Verwendung von certifi.where() umgeht das Problem in jedem Fall.

Windows

Unter Windows lädt Python Zertifikate aus dem Windows-Zertifikatspeicher. Fehler haben typischerweise eine von zwei Ursachen:

  • Ein veralteter Root-Store auf einem Rechner ohne Updates, sodass eine neuere Root fehlt. Installieren Sie Windows-Updates oder verwenden Sie certifi.
  • TLS-Inspektion durch einen Virenscanner oder einen Firmen-Proxy, was zu self-signed certificate in certificate chain führt. Prüfen Sie den Aussteller, den das Skript aus Schritt 1 ausgibt; nennt er ein Sicherheitsprodukt, fängt dieses Produkt die Verbindung ab.

Besonders häufig ist der veraltete Root-Store auf Industrie-PCs und Edge-Gateways in der Fertigung, die oft jahrelang ohne Betriebssystem-Updates in einem abgeschotteten OT-Netz laufen. Hier ist ein mit der Anwendung ausgeliefertes, gepflegtes CA-Bundle (etwa certifi) meist robuster als der Store des Betriebssystems. Nehmen Sie die Aktualisierung des Bundles in Ihren Patch-Prozess für die Anlage auf.

Linux

Python nutzt die Standardpfade von OpenSSL, unter Debian und Ubuntu meist /etc/ssl/certs/ca-certificates.crt, auf Red-Hat-basierten Systemen /etc/pki/tls/certs/ca-bundle.crt. Fehlt das Paket oder ist es veraltet:

# Debian / Ubuntu / Raspberry Pi OS
sudo apt update && sudo apt install --reinstall ca-certificates
sudo update-ca-certificates

# Fedora / RHEL
sudo dnf reinstall ca-certificates

Docker und schlanke Images

Images wie python:3.12-slim enthalten meist CA-Zertifikate, alpine- und Distroless-Varianten aber unter Umständen nicht. Fügen Sie das Paket explizit hinzu:

FROM python:3.12-alpine
RUN apk add --no-cache ca-certificates

Oder installieren Sie certifi im Image und verweisen Sie im Code darauf. Sie können OpenSSL auch über die Umgebungsvariable SSL_CERT_FILE auf ein Bundle verweisen.

Die Variante Hostname Mismatch

Hostname mismatch erscheint, wenn Sie client.connect("203.0.113.10", 8883) aufrufen oder einen internen Alias verwenden, der nicht im Zertifikat steht. TLS prüft, ob der angefragte Name in den Subject Alternative Names des Zertifikats vorkommt. Verbinden Sie sich mit dem echten Hostnamen des Brokers. Für ConnectMQ ist das broker.connectmq.com. Wenn Sie zum Testen eine bestimmte IP erzwingen müssen, tragen Sie sie in Ihre hosts-Datei ein, statt sich per IP zu verbinden.

Private oder selbstsignierte Broker

Wenn Sie Ihren eigenen Broker mit einer privaten CA betreiben, wird ihm das öffentliche CA-Bundle nie vertrauen. Übergeben Sie die private CA explizit mit client.tls_set(ca_certs="my-ca.crt") und stellen Sie sicher, dass das Broker-Zertifikat den korrekten Hostnamen in seinem SAN enthält. Der Ablauf und der damit verbundene Wartungsaufwand werden unter selbstsignierte Zertifikate für MQTT erklärt.

Die Kette mit OpenSSL untersuchen

Wenn die Ausgabe von Python nicht genügt, zeigt OpenSSL die genaue Kette, die der Server sendet, und wo die Prüfung abbricht:

openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -showcerts </dev/null

Lesen Sie den Abschnitt Certificate chain von oben: Eintrag 0 ist das Broker-Zertifikat, die folgenden Einträge sind Zwischenzertifikate, und jede i:-Zeile (Aussteller) sollte zur s:-Zeile (Subject) des nächsten Eintrags passen. Der abschließende Verify return code sagt Ihnen, ob der eigene Trust Store von OpenSSL die Kette akzeptiert. Meldet OpenSSL 0 (ok), Python aber scheitert, nutzt Python einen anderen Trust Store als OpenSSL; die Ausgabe von ssl.get_default_verify_paths() wie in Schritt 1 deckt das meist auf. Nennt der Aussteller von Eintrag 0 den Hersteller Ihres Virenscanners oder Ihrer Firewall, sehen Sie TLS-Inspektion statt des echten Broker-Zertifikats.

Um gezielt gegen certifi zu vergleichen, ergänzen Sie -CAfile mit dem Pfad, den python -c "import certifi; print(certifi.where())" ausgibt. Erfolg mit certifi und Fehlschlag ohne bestätigen, dass der Store des Betriebssystems das Problem ist.

Was Sie nicht tun sollten

Suchergebnisse schlagen oft diese Zeilen vor:

client.tls_set(cert_reqs=ssl.CERT_NONE)
client.tls_insecure_set(True)

Sie lassen den Fehler verschwinden, indem sie die Serverauthentifizierung deaktivieren. Ihre Zugangsdaten gehen dann an jeden Server, der antwortet, auch an den eines Angreifers. Verwenden Sie sie, wenn überhaupt, nur für ein paar Minuten lokales Debugging gegen einen Labor-Broker, niemals in Code, der committet wird. Der Artikel zu den Best Practices für MQTT-Sicherheit erklärt, warum die Authentifizierung des Brokers genauso wichtig ist wie die Verschlüsselung.

Checkliste für die schnelle Lösung

  1. Lesen Sie das Detail nach certificate verify failed.
  2. Führen Sie das Skript aus Schritt 1 in derselben Umgebung aus.
  3. Verwenden Sie certifi.where() als ca_certs oder reparieren Sie den Store des Betriebssystems.
  4. Verbinden Sie sich per Hostname, nicht per IP.
  5. Prüfen Sie mit date -u auf Uhrzeitprobleme.
  6. Sehen Sie sich den Zertifikatsaussteller an, um Proxys zu erkennen.
  7. Stellen Sie bei privaten Brokern Ihre eigene CA-Datei bereit.

Wenn Sie nach der Behebung des Handshakes immer noch nicht weiterkommen, behandelt unser Leitfaden zur Behebung von MQTT-TLS-Handshake-Fehlern Ports, SNI und Protokollversionen, und das Tutorial zu Python MQTT TLS zeigt vollständige Muster für die Produktion.

Warum öffentliche Zertifikate Zeit sparen

Die meisten Fehler bei der Zertifikatsprüfung verschwinden, wenn der Broker ein Zertifikat einer öffentlich vertrauenswürdigen CA verwendet und es automatisch erneuert. Genau so funktioniert ConnectMQ: ein verwalteter MQTT-Broker mit einem Let's-Encrypt-Zertifikat auf den Ports 8883 und 8084, sodass Standard-Python-Installationen es ohne zusätzliche Dateien verifizieren. Sie können jeden Test aus diesem Artikel auf dem kostenlosen öffentlichen MQTT-Broker nachvollziehen, der für Tests und nicht für Produktionsdaten gedacht ist, bevor Sie auf private Zugangsdaten umsteigen.

Starten Sie mit ConnectMQ

Registrieren Sie sich unter app.connectmq.com, wählen Sie den kostenlosen Serverless-Plan ohne Kreditkarte, erstellen Sie einen Broker und führen Sie das obige paho-mqtt-Beispiel mit Ihrem generierten Benutzernamen, Passwort und Ihrer Client ID aus.

Häufig gestellte Fragen

Warum funktioniert derselbe Code unter Linux, aber nicht unter macOS?

Der macOS-Build von python.org wird ohne CA-Zertifikate ausgeliefert, bis Sie „Install Certificates.command“ ausführen. Python unter Linux nutzt das System-Bundle, das in der Regel bereits installiert ist.

Ist es sicher, certifi statt des Stores des Betriebssystems zu verwenden?

Ja. certifi enthält die kuratierte Root-Liste von Mozilla. Halten Sie es einfach per pip aktuell, und beachten Sie, dass es keine privaten oder unternehmensinternen CAs enthält.

Bedeutet dieser Fehler, dass der Broker kompromittiert ist?

Selten. Fehlende CA-Bundles, falsche Hostnamen, Uhrzeitprobleme und TLS-Inspektion sind weitaus häufiger. Prüfen Sie zur Sicherheit den Ausstellernamen.

Brauche ich die Zertifikatsdatei von ConnectMQ?

Nein. ConnectMQ verwendet ein öffentlich vertrauenswürdiges Let's-Encrypt-Zertifikat, sodass ein Standard-CA-Bundle wie certifi oder der Store des Betriebssystems ausreicht.

Verwandte Artikel

MQTT-Zugangsdaten ohne Ausfallzeit rotieren

Eine Schritt-für-Schritt-Strategie mit zwei parallelen Zugangsdaten, um MQTT-Benutzernamen und -Passwörter in einer Geräteflotte zu rotieren: neue Zugangsdaten bereitstellen, mit Fallback umschalten, prüfen und erst dann die alten widerrufen.

7 Min. Lesezeit

MQTT-Zugangsdaten sicher auf Embedded-Geräten speichern

Ein praxisnaher Vergleich der Möglichkeiten, MQTT-Benutzernamen und -Passwörter auf ESP32- und Linux-Geräten zu schützen, von verschlüsseltem NVS und Flash-Verschlüsselung bis zu Secure Elements und TPM-gestützten systemd-Credentials.

8 Min. Lesezeit

MQTT-Zugriffskontrolllisten (ACLs): Konzepte und Design

Was MQTT-Zugriffskontrolllisten sind, wie Broker wie Mosquitto Lese- und Schreibregeln auf Topic-Ebene ausdrücken, wie sich abgelehnte Operationen verhalten und wie Sie Topic-Namespaces so entwerfen, dass die Autorisierung einfach bleibt.

7 Min. Lesezeit

Alle Artikel →

Ihr privater MQTT-Broker ist nur wenige Klicks entfernt

Konto anlegen, Broker-Zugangsdaten erhalten und das erste Gerät verbinden — ohne Server, die installiert, gepatcht oder skaliert werden müssen.