Fondamentaux MQTT

Client ID MQTT : bonnes pratiques d'unicité, de format et de takeover

Le client ID est ce qui permet à un broker MQTT de savoir qui vous êtes. Mal choisi, il pousse les appareils à se déconnecter mutuellement ou à perdre leur session. Voici les règles, formats et étapes de diagnostic qui fonctionnent.

Illustration du client ID MQTT montrant deux appareils avec le même identifiant qui se disputent une même connexion au broker
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Le client ID MQTT est l'identifiant qu'un client envoie dans le paquet CONNECT ; le broker s'en sert pour distinguer les connexions et les sessions. Ce guide explique pourquoi deux clients portant le même ID n'arrêtent pas de se déconnecter l'un l'autre, comment concevoir des formats d'ID qui passent d'un prototype unique à une flotte entière, et comment diagnostiquer rapidement les takeovers lors de tests sur un broker public.

À quoi sert le client ID MQTT

Chaque paquet CONNECT contient un champ Client Identifier. Le broker MQTT l'utilise pour trois choses :

  1. L'unicité des connexions. Une seule connexion réseau par client ID peut être active à un instant donné.
  2. La recherche de session. L'état d'une session persistante (abonnements et messages en file d'attente) est stocké sous le client ID.
  3. L'exploitation. Les journaux, les événements de connexion et les topics de supervision désignent les clients par leur ID.

Ce n'est pas en soi un identifiant d'authentification. Toute personne capable de se connecter peut revendiquer n'importe quel ID, sauf si le broker lie les ID aux identifiants de connexion. Sur les brokers privés ConnectMQ, les client ID sont liés aux identifiants délivrés dans le portail : un autre utilisateur ne peut donc pas réutiliser l'ID de votre appareil.

Pourquoi des client ID en double se déconnectent mutuellement

La spécification est explicite : si un client se connecte avec un ID déjà connecté, le broker doit déconnecter le client existant. C'est ce qu'on appelle un session takeover (prise de contrôle de session). Ce mécanisme existe pour qu'un appareil ayant perdu silencieusement sa connexion puisse se reconnecter immédiatement, sans attendre que l'ancien socket expire.

Le problème survient lorsque deux clients différents partagent un ID. La séquence est la suivante :

  1. Le client A se connecte en tant que sensor-01.
  2. Le client B se connecte en tant que sensor-01. Le broker déconnecte A.
  3. La reconnexion automatique de A se déclenche et il se connecte en tant que sensor-01. Le broker déconnecte B.
  4. B se reconnecte... et la boucle se répète toutes les quelques secondes.

Les symptômes : des journaux de connexion/déconnexion incessants, des messages manqués, des messages de testament (will) envoyés à répétition et un indicateur « en ligne/hors ligne » qui clignote. En MQTT 5, le client éjecté reçoit un DISCONNECT avec le reason code 0x8E (Session taken over), ce qui facilite grandement le diagnostic par rapport à 3.1.1, où le socket se ferme simplement.

Causes fréquentes

  • La même image de firmware flashée sur de nombreuses cartes avec un ID codé en dur.
  • Du code d'exemple copié-collé avec un ID comme test ou esp32client.
  • Un service exécuté dans plusieurs conteneurs ou pods avec le même ID configuré.
  • Un développeur qui lance le même script dans deux terminaux.
  • Un outil MQTT de bureau et un appareil qui utilisent tous deux l'ID de l'appareil.

Concevoir un format de client ID MQTT

Un bon ID est unique, stable, lisible et accepté par tous les brokers.

Règles de format

Règle Pourquoi
N'utiliser que a-z, A-Z, 0-9, - et _ Tous les brokers doivent accepter ces caractères
Rester court, idéalement 23 caractères ou moins MQTT 3.1.1 ne garantit la prise en charge que jusqu'à 23 octets ; la plupart des brokers acceptent davantage
Ne jamais le laisser vide en production Un ID vide empêche les sessions persistantes, et de nombreux brokers le rejettent
Le garder stable pour les appareils avec session Un ID qui change signifie une nouvelle session à chaque fois
Le rendre unique pour chaque instance en cours d'exécution Évite les boucles de takeover
Éviter les secrets et les données personnelles Les ID apparaissent dans les journaux et la supervision

Modèles qui fonctionnent

  • Appareils : un préfixe suivi d'un identifiant dérivé du matériel, par exemple env- suivi des derniers octets de l'adresse MAC (env-a4cf12b3), ou un numéro de série issu de votre base de données de fabrication.
  • Services backend : le nom du service suivi d'un identifiant d'instance, comme alarm-worker-0 à partir de l'ordinal d'un StatefulSet. Si les instances sont totalement interchangeables et n'ont pas besoin de session, un suffixe aléatoire convient.
  • Tableaux de bord dans le navigateur : un préfixe suivi d'une chaîne aléatoire par onglet, avec des sessions propres, car personne n'a besoin de reprendre la session d'un tableau de bord.
  • Scripts de test : un suffixe aléatoire à chaque exécution, par exemple test- suivi de 6 caractères hexadécimaux aléatoires.

Générer des ID dans le code

En Python, avec l'adresse MAC pour un ID d'appareil stable ou un jeton aléatoire pour les clients de test :

import secrets
import uuid
import paho.mqtt.client as mqtt

def device_client_id(prefix: str = "env") -> str:
    mac = uuid.getnode()            # adresse matérielle 48 bits sous forme d'entier
    return f"{prefix}-{mac:012x}"   # ex. env-a4cf12b3c4d5

def test_client_id(prefix: str = "test") -> str:
    return f"{prefix}-{secrets.token_hex(3)}"  # ex. test-9f2c1a

client_id = device_client_id()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=client_id,
                     protocol=mqtt.MQTTv5)
print("Using client ID:", client_id)

Sur ESP32 avec PubSubClient, en dérivant l'ID de l'adresse MAC stockée dans l'efuse :

#include <WiFi.h>
#include <PubSubClient.h>

WiFiClient net;
PubSubClient mqttClient(net);

String makeClientId() {
  uint64_t mac = ESP.getEfuseMac();
  char id[24];
  snprintf(id, sizeof(id), "env-%04x%08x",
           (uint16_t)(mac >> 32), (uint32_t)mac);
  return String(id);
}

void connectMqtt() {
  String clientId = makeClientId();
  mqttClient.setServer("broker.connectmq.com", 1883);
  while (!mqttClient.connected()) {
    if (mqttClient.connect(clientId.c_str())) {
      Serial.println("Connected as " + clientId);
    } else {
      Serial.printf("Failed, state=%d. Retrying in 5 s\n", mqttClient.state());
      delay(5000);
    }
  }
}

La configuration complète de la carte, Wi-Fi compris, se trouve dans le tutoriel ESP32 MQTT.

Client ID vides et identifiants attribués

MQTT 3.1.1 n'autorise un client ID de longueur nulle qu'avec clean session à true ; le broker en invente alors un en interne. MQTT 5 va plus loin : le broker renvoie un Assigned Client Identifier dans le CONNACK pour que le client connaisse son nom. C'est pratique pour les clients jetables, mais cela exclut les sessions persistantes, car vous ne pouvez pas vous reconnecter sous une identité que vous ne maîtrisez pas. De nombreux brokers, dont le serveur MQTT public gratuit de ConnectMQ, exigent tout simplement un ID non vide, ce qui est de toute façon l'habitude la plus sûre.

Comment détecter un takeover de client ID

Voici un test reproductible sur le serveur MQTT public gratuit. Utilisez votre propre suffixe aléatoire et n'oubliez pas que ce serveur, réservé aux tests, est lisible par tous.

  1. Dans un premier terminal, connectez-vous avec un ID et la sortie de débogage :
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i dup-demo-k7q1 -d -t 'connectmq/demo/k7q1/#'
  1. Dans un deuxième terminal, lancez exactement la même commande.
  2. Le premier terminal est immédiatement déconnecté ; avec -d, vous voyez le broker fermer sa connexion. Selon votre version de mosquitto, il s'arrête ou se reconnecte ; dans ce dernier cas, les deux terminaux commencent à s'éjecter mutuellement, exactement comme dans la boucle décrite plus haut.
  3. Dans un troisième terminal, observez la vue qu'a le broker de ce client :
mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-k7q1 -v \
  -t '$SYS/broker/connection/dup-demo-k7q1/state'

En production, une liste de vérification rapide lorsque des appareils oscillent entre connecté et déconnecté :

  1. Rassemblez les client ID de tous les appareils suspects et cherchez les doublons.
  2. Vérifiez si les reason codes de déconnexion indiquent 0x8E (session taken over).
  3. Comparez les changements d'état de connexion avec les horodatages de reconnexion de chaque appareil ; une alternance révèle deux clients qui se disputent un même ID.
  4. Fermez les outils de bureau ou les sessions VS Code susceptibles d'utiliser l'ID d'un appareil.
  5. Si les oscillations persistent avec des ID uniques, examinez plutôt le keep alive et les timeouts réseau.

Les client ID MQTT en production

Quelques habitudes d'exploitation évitent la plupart des incidents liés aux client ID. Générez les ID lors du provisionnement plutôt qu'à l'exécution, afin qu'un même appareil reçoive toujours le même ID, même après une réinitialisation d'usine. Stockez l'ID à côté des identifiants de l'appareil pour que l'équipe de support puisse rapprocher les entrées de journal du matériel. Lorsque vous remplacez une unité défectueuse, décidez sciemment si le nouvel appareil hérite de l'ancien ID (et de sa session) ou en reçoit un nouveau. Pour les services, faites provenir l'identifiant d'instance de votre orchestrateur plutôt que d'un fichier de configuration partagé par toutes les réplicas.

À mesure que les flottes grandissent, intégrez les client ID à votre processus de provisionnement : enregistrez-les avec les numéros de série, dérivez-les du matériel et ne réutilisez jamais un ID pour un autre appareil physique. Si vous apprenez MQTT depuis le début, le tutoriel MQTT explique comment les ID, les sessions et les topics s'articulent.

Gérer les client ID en toute sécurité avec ConnectMQ

ConnectMQ est un broker MQTT managé qui délivre un nom d'utilisateur, un mot de passe et un client ID pour chaque broker que vous créez, et qui lie les client ID à ces identifiants afin que les autres locataires ne puissent pas les détourner. L'état des connexions est visible en direct dans le portail, ce qui permet de repérer facilement les boucles de takeover. Créez un broker Serverless gratuit sans carte bancaire et connectez-vous avec YOUR_USERNAME, YOUR_PASSWORD et YOUR_CLIENT_ID.

Questions fréquentes

Que se passe-t-il si deux clients MQTT utilisent le même client ID ?

Le broker déconnecte le client déjà connecté et conserve le nouveau. Si les deux clients se reconnectent automatiquement, ils continuent à s'éjecter mutuellement en boucle.

Quelle longueur peut avoir un client ID MQTT ?

MQTT 3.1.1 garantit la prise en charge de 1 à 23 octets de lettres et de chiffres, et les brokers peuvent accepter des ID plus longs et davantage de caractères. Des ID courts, alphanumériques avec des tirets, constituent le choix le plus portable.

Le client ID MQTT doit-il être aléatoire ?

Utilisez un ID aléatoire pour les clients éphémères ou interchangeables qui n'ont pas besoin de session. Les appareils et services qui s'appuient sur des sessions persistantes ont besoin d'un ID stable et unique qui reste identique d'une reconnexion à l'autre.

Le client ID est-il un identifiant de sécurité ?

Non. Considérez-le uniquement comme un identifiant et authentifiez-vous toujours avec un nom d'utilisateur et un mot de passe ou des certificats ; les brokers qui lient les ID aux identifiants de connexion, comme le fait ConnectMQ, ajoutent une protection contre l'usurpation d'identité.

Articles liés

Qui a inventé MQTT ? L'histoire, des oléoducs à l'IoT

MQTT a été inventé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nipper (Arcom) pour surveiller des oléoducs par satellite. Suivez son parcours vers l'open source, OASIS, l'ISO et les brokers MQTT managés d'aujourd'hui.

8 min de lecture

Pourquoi votre client MQTT se déconnecte sans cesse (et comment y remédier)

Les boucles de reconnexion sont l'un des problèmes MQTT les plus courants. Découvrez les cinq causes habituelles, des client ID en double aux timeouts de keep alive et aux paquets trop volumineux, et suivez une méthode de diagnostic qui identifie la vôtre.

9 min de lecture

Taille maximale d'un message MQTT : limites et stratégies pour les gros payloads

MQTT peut techniquement transporter un paquet de 256 Mo, mais les brokers, les bibliothèques clientes et les appareils imposent des limites bien plus basses. Découvrez où se trouvent les vraies limites, ce qui se passe quand on les dépasse et comment envoyer de gros payloads.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.