Tests de brokers

Comment tester une connexion MQTT TLS (openssl, mosquitto, code)

Testez MQTT sur TLS port 8883 : vérifications openssl s_client, chaîne de certificats, SNI et nom d'hôte, mosquitto --cafile et solutions aux erreurs courantes.

Mis à jour · 9 min de lecture

Comment tester une connexion MQTT TLS (openssl, mosquitto, code)

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.

Vérification TLS de base
openssl s_client -connect broker.connectmq.com:8883 \
  -servername broker.connectmq.com \
  -verify_hostname broker.connectmq.com \
  -showcerts </dev/null

Le rôle de chaque option :

  • -servername envoie 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_hostname demande à openssl de vérifier que le certificat est valide pour ce nom — la même vérification que fait votre client MQTT.
  • -showcerts affiche chaque certificat envoyé par le serveur, pour voir si l'intermédiaire est inclus.
  • </dev/null ferme la connexion juste après le handshake au lieu d'attendre une saisie.

À la fin de la sortie, cherchez :

Résultat sain
Verify return code: 0 (ok)

Tout autre résultat est un problème que vous verrez aussi dans votre client MQTT :

Résultat opensslSignification
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 numberCe port parle MQTT en clair, pas TLS (souvent 1883)
connect: Connection refused / timeoutPort 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

Subject, issuer, SAN et expiration
openssl s_client -connect broker.connectmq.com:8883 \
  -servername broker.connectmq.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

Vé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 :

Terminal 1 — abonnement sur TLS
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 -d
Terminal 2 — publication sur TLS
mosquitto_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.

tls_check.py (paho-mqtt 2.x)
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()
tls-check.mjs (MQTT.js 5)
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èqueErreurCause habituelle
Python[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificateCA ou intermédiaire manquant
Pythoncertificate verify failed: Hostname mismatch, certificate is not valid for '...'Connexion par IP ou avec un mauvais nom
Python[SSL: WRONG_VERSION_NUMBER] wrong version numberClient TLS sur un port en clair
Node.jsUNABLE_TO_VERIFY_LEAF_SIGNATURE — unable to verify the first certificateLe serveur n'envoie pas l'intermédiaire
Node.jsSELF_SIGNED_CERT_IN_CHAINCA privée non fournie dans ca
Node.jsERR_TLS_CERT_ALTNAME_INVALID — Hostname/IP does not match certificate's altnamesNom 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

  1. openssl s_client avec -servername et -verify_hostname renvoie Verify return code: 0 (ok).
  2. -showcerts affiche le certificat serveur et l'intermédiaire.
  3. Le SAN contient exactement le nom d'hôte utilisé par les clients ; le certificat n'est pas près d'expirer.
  4. mosquitto_sub et mosquitto_pub échangent un message sur 8883 avec la vérification active.
  5. La bibliothèque de votre application se connecte avec son magasin de confiance par défaut (ou la CA privée que vous livrez).
  6. Le port en clair 1883 est fermé ou désactivé en production si TLS est obligatoire.
  7. 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.