Pour tester une connexion MQTT TLS, vérifiez trois couches dans l'ordre : le handshake TLS lui-même avec openssl s_client, puis une vraie session MQTT avec mosquitto_sub ou mosquitto_pub, enfin la bibliothèque cliente utilisée par vos appareils. Chaque couche peut échouer pour des raisons différentes, et les tester séparément vous indique exactement laquelle est en cause.
Tous les exemples utilisent broker.connectmq.com sur le port 8883 (MQTT sur TLS). Remplacez l'hôte par celui de votre broker.
Étape 1 : vérifier le handshake avec openssl
openssl s_client parle TLS mais pas MQTT, et c'est exactement ce qu'il vous faut : il montre le certificat envoyé par le broker et si votre machine lui fait confiance, sans aucune bibliothèque MQTT entre les deux.
openssl s_client -connect broker.connectmq.com:8883 \
-servername broker.connectmq.com \
-verify_hostname broker.connectmq.com \
-showcerts </dev/nullLe rôle de chaque option :
-servernameenvoie le SNI (Server Name Indication). Les brokers et load balancers qui hébergent plusieurs noms s'en servent pour choisir le certificat. Sans lui, vous pouvez recevoir un certificat par défaut et une erreur de nom d'hôte.-verify_hostnamedemande à openssl de vérifier que le certificat est valide pour ce nom — la même vérification que fait votre client MQTT.-showcertsaffiche chaque certificat envoyé par le serveur, pour voir si l'intermédiaire est inclus.</dev/nullferme la connexion juste après le handshake au lieu d'attendre une saisie.
À la fin de la sortie, cherchez :
Verify return code: 0 (ok)Tout autre résultat est un problème que vous verrez aussi dans votre client MQTT :
| Résultat openssl | Signification |
|---|---|
Verify return code: 20 (unable to get local issuer certificate) | La CA (ou un intermédiaire manquant) n'est pas dans votre magasin de confiance |
Verify return code: 18 (self-signed certificate) | Le certificat serveur est auto-signé ; passez sa CA avec -CAfile |
Verify return code: 19 (self-signed certificate in certificate chain) | La chaîne se termine par une racine privée à laquelle vous ne faites pas confiance |
Verify return code: 10 (certificate has expired) | Renouvelez le certificat sur le broker |
Verify return code: 62 (hostname mismatch) | Le certificat ne contient pas le nom auquel vous vous êtes connecté |
wrong version number | Ce port parle MQTT en clair, pas TLS (souvent 1883) |
connect: Connection refused / timeout | Port fermé ou filtré — ce n'est pas un problème TLS |
Pour un broker avec une CA privée, ajoutez -CAfile ca.crt et relancez la commande. Si elle renvoie alors 0 (ok), vos certificats sont corrects et le client n'a besoin que du même fichier de CA.
Inspecter rapidement le certificat
openssl s_client -connect broker.connectmq.com:8883 \
-servername broker.connectmq.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNameVérifiez que subjectAltName contient exactement le nom d'hôte utilisé par vos appareils. Les clients modernes ignorent le Common Name du certificat : un nom présent uniquement dans le CN ne compte pas. Pour une vérification en CI qui échoue deux semaines avant l'expiration, envoyez le certificat dans openssl x509 -noout -checkend 1209600.
Pour tester les versions de TLS acceptées par le broker, relancez la première commande avec -tls1_2 ou -tls1_3. Un appareil doté d'une ancienne pile TLS qui ne parle que TLS 1.2 a besoin que le broker garde la 1.2 activée — voir TLS 1.2 vs 1.3 pour MQTT.
Étape 2 : ouvrir une vraie session MQTT sur TLS
Un handshake réussi ne prouve pas que le listener MQTT derrière fonctionne. Abonnez-vous et publiez sur 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"Les clients mosquitto n'activent TLS que si vous leur donnez une option de CA. Utilisez --cafile avec votre bundle de CA (le chemin ci-dessus est celui de Debian/Ubuntu ; sur macOS avec Homebrew, il se trouve sous $(brew --prefix)/etc/ca-certificates/cert.pem), --capath /etc/ssl/certs ou --tls-use-os-certs avec mosquitto 2.x. Pour une CA privée, pointez --cafile vers votre ca.crt. Pour le TLS mutuel, ajoutez --cert client.crt --key client.key — voir certificats clients et mTLS.
En cas d'échec, mosquitto est laconique : il affiche Error: A TLS error occurred. et rien de plus. Revenez à l'étape 1 — openssl vous dit pourquoi. Si openssl réussit mais que mosquitto échoue, comparez le nom d'hôte : -h doit être le nom présent dans le certificat, pas une adresse IP.
Étape 3 : tester depuis le code client
Enfin, testez avec la bibliothèque qu'utilise votre application. Le magasin de certificats et les valeurs par défaut varient selon le langage : une connexion qui marche avec mosquitto peut encore échouer ici.
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() # CA système, vérification du nom d'hôte active ; ca_certs="ca.crt" pour une CA privée
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"), // uniquement pour une CA privée
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));Les erreurs qu'ils produisent sont celles que l'on recherche le plus :
| Bibliothèque | Erreur | Cause habituelle |
|---|---|---|
| Python | [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate | CA ou intermédiaire manquant |
| Python | certificate verify failed: Hostname mismatch, certificate is not valid for '...' | Connexion par IP ou avec un mauvais nom |
| Python | [SSL: WRONG_VERSION_NUMBER] wrong version number | Client TLS sur un port en clair |
| Node.js | UNABLE_TO_VERIFY_LEAF_SIGNATURE — unable to verify the first certificate | Le serveur n'envoie pas l'intermédiaire |
| Node.js | SELF_SIGNED_CERT_IN_CHAIN | CA privée non fournie dans ca |
| Node.js | ERR_TLS_CERT_ALTNAME_INVALID — Hostname/IP does not match certificate's altnames | Nom absent de la liste SAN |
Les corrections sont détaillées une par une dans certificate verify failed, échec du handshake TLS et hostname mismatch. Le générateur de code produit des extraits de connexion TLS pour d'autres langages.
Checklist rapide des tests TLS
openssl s_clientavec-servernameet-verify_hostnamerenvoieVerify return code: 0 (ok).-showcertsaffiche le certificat serveur et l'intermédiaire.- Le SAN contient exactement le nom d'hôte utilisé par les clients ; le certificat n'est pas près d'expirer.
mosquitto_subetmosquitto_pubéchangent un message sur8883avec la vérification active.- La bibliothèque de votre application se connecte avec son magasin de confiance par défaut (ou la CA privée que vous livrez).
- Le port en clair
1883est fermé ou désactivé en production si TLS est obligatoire. - Les appareils dotés d'anciennes piles TLS se connectent avec la version de TLS et les suites de chiffrement que vous autorisez.
Vous voulez aussi une vérification depuis le navigateur ? Le client MQTT en ligne se connecte en WebSockets sécurisés sur 8084, qui utilise le même certificat dans de nombreuses configurations — un moyen rapide de valider le côté TLS du broker avant de déboguer un appareil.
Tester TLS couche par couche transforme une vague « erreur TLS » en cause précise en quelques minutes. Gardez la commande openssl et la vérification d'expiration dans vos scripts, et lancez-les à chaque renouvellement de certificat ou changement de load balancer.
Questions fréquentes
Comment vérifier qu'un broker MQTT prend en charge TLS ?
Lancez openssl s_client -connect host:8883 -servername host. Si le handshake réussit, vous voyez la chaîne de certificats et 'Verify return code: 0 (ok)'. Une erreur 'wrong version number' signifie que le port parle MQTT en clair, pas TLS.
Pourquoi TLS fonctionne-t-il dans mon navigateur mais pas sur mon appareil ?
Le plus souvent, le serveur n'envoie pas son certificat intermédiaire. Les navigateurs savent récupérer eux-mêmes les intermédiaires manquants ; openssl, mosquitto et les piles TLS embarquées non. Vérifiez que s_client -showcerts affiche l'intermédiaire et corrigez le fichier de certificat du broker.
Est-il sûr d'utiliser --insecure ou tls_insecure_set(True) ?
Uniquement comme diagnostic temporaire sur votre propre machine. Ces options désactivent la vérification du nom d'hôte et exposent la connexion aux attaques man-in-the-middle. Corrigez plutôt le certificat ou le nom d'hôte et gardez la vérification active.
