El client ID de MQTT es el identificador que un cliente envía en el CONNECT, y el broker lo usa para distinguir conexiones y sesiones. Esta guía explica por qué dos clientes con el mismo ID se desconectan mutuamente una y otra vez, cómo diseñar formatos de ID que escalen desde un prototipo hasta una flota y cómo diagnosticar rápidamente los takeovers cuando pruebas en un broker público.
Para qué se usa el client ID de MQTT
Todo paquete CONNECT lleva un campo Client Identifier. El broker MQTT lo usa para tres cosas:
- Unicidad de la conexión. Solo puede haber una conexión de red activa por client ID a la vez.
- Búsqueda de la sesión. El estado de la sesión persistente (suscripciones y mensajes encolados) se guarda asociado al client ID.
- Operaciones. Los logs, los eventos de conexión y los topics de monitorización se refieren a los clientes por su ID.
Por sí solo, no es una credencial de autenticación. Cualquiera que pueda conectarse puede reclamar cualquier ID, salvo que el broker vincule los IDs a credenciales. En los brokers privados de ConnectMQ, los client IDs están vinculados a las credenciales emitidas en el portal, así que otro usuario no puede reutilizar el ID de tu dispositivo.
Por qué los client IDs duplicados se expulsan entre sí
La especificación es explícita: si un cliente se conecta con un ID que ya está conectado, el broker debe desconectar al cliente existente. Esto se llama session takeover. Existe para que un dispositivo que perdió su conexión sin avisar pueda reconectarse de inmediato sin esperar a que expire el socket antiguo.
El problema aparece cuando dos clientes distintos comparten un ID. La secuencia es esta:
- El cliente A se conecta como
sensor-01. - El cliente B se conecta como
sensor-01. El broker desconecta a A. - La reconexión automática de A se dispara y se conecta como
sensor-01. El broker desconecta a B. - B se reconecta... y el bucle se repite cada pocos segundos.
Los síntomas incluyen logs constantes de conexión y desconexión, mensajes perdidos, mensajes de will disparados repetidamente y un indicador "online/offline" que parpadea. En MQTT 5, el cliente expulsado recibe un DISCONNECT con el reason code 0x8E (Session taken over), lo que facilita mucho el diagnóstico frente a 3.1.1, donde el socket simplemente se cierra.
Causas habituales
- La misma imagen de firmware grabada en muchas placas con un ID fijo en el código.
- Código de ejemplo copiado y pegado con un ID como
testoesp32client. - Un servicio que se ejecuta en varios contenedores o pods con el mismo ID configurado.
- Un desarrollador que ejecuta el mismo script en dos terminales.
- Una herramienta MQTT de escritorio y un dispositivo que usan el ID del dispositivo.
Cómo diseñar un formato de client ID de MQTT
Los buenos IDs son únicos, estables, legibles y seguros para cualquier broker.
Reglas de formato
| Regla | Por qué |
|---|---|
Usa solo a-z, A-Z, 0-9, - y _ |
Todos los brokers deben aceptar estos caracteres |
| Mantenlo corto, idealmente de 23 caracteres o menos | MQTT 3.1.1 solo garantiza soporte hasta 23 bytes; la mayoría de los brokers permiten más |
| No lo dejes nunca vacío en producción | Los IDs vacíos impiden las sesiones persistentes y muchos brokers los rechazan |
| Hazlo estable en dispositivos con sesiones | Un ID que cambia implica una sesión nueva cada vez |
| Hazlo único por instancia en ejecución | Evita los bucles de takeover |
| Evita secretos y datos personales | Los IDs aparecen en logs y en la monitorización |
Patrones que funcionan
- Dispositivos: un prefijo más un identificador derivado del hardware, como
env-más los últimos bytes de la dirección MAC (env-a4cf12b3), o un número de serie de tu base de datos de fabricación. - Servicios backend: nombre del servicio más identificador de instancia, como
alarm-worker-0a partir del ordinal de un StatefulSet. Si las instancias son totalmente intercambiables y no necesitan sesiones, un sufijo aleatorio sirve. - Dashboards de navegador: un prefijo más una cadena aleatoria por pestaña, con sesiones limpias, porque nadie necesita reanudar la sesión de un dashboard.
- Scripts de prueba: un sufijo aleatorio en cada ejecución, por ejemplo
test-más 6 caracteres hexadecimales aleatorios.
Cómo generar IDs en código
Python, usando la dirección MAC para un ID de dispositivo estable o un token aleatorio para clientes de prueba:
import secrets
import uuid
import paho.mqtt.client as mqtt
def device_client_id(prefix: str = "env") -> str:
mac = uuid.getnode() # dirección hardware de 48 bits como entero
return f"{prefix}-{mac:012x}" # p. ej. env-a4cf12b3c4d5
def test_client_id(prefix: str = "test") -> str:
return f"{prefix}-{secrets.token_hex(3)}" # p. ej. 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)
ESP32 con PubSubClient, derivando el ID de la MAC del 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 configuración completa de la placa, Wi-Fi incluido, está en el tutorial de MQTT con ESP32.
Client IDs vacíos e identificadores asignados
MQTT 3.1.1 permite un client ID de longitud cero solo con clean session a true; en ese caso el broker inventa uno internamente. MQTT 5 va más allá: el broker devuelve un Assigned Client Identifier en el CONNACK para que el cliente conozca su nombre. Es práctico para clientes desechables, pero descarta las sesiones persistentes, porque no puedes reconectarte con una identidad que no controlas. Muchos brokers, incluido el servidor MQTT público gratuito de ConnectMQ, simplemente exigen un ID no vacío, que en cualquier caso es el hábito más seguro.
Cómo detectar un takeover de client ID
Aquí tienes una prueba reproducible en el servidor MQTT público gratuito. Usa tu propio sufijo aleatorio y recuerda que cualquiera puede leer el área pública: sirve para pruebas y prototipos, no para datos de producción.
- En el primer terminal, conéctate con un ID y salida de depuración:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
-i dup-demo-k7q1 -d -t 'connectmq/demo/k7q1/#'
- En el segundo terminal, ejecuta exactamente el mismo comando.
- El primer terminal se desconecta de inmediato; con
-dpuedes ver cómo el broker cierra su conexión. Según tu versión de mosquitto, o bien termina o bien se reconecta, y en ese caso los dos terminales empiezan a expulsarse mutuamente, que es exactamente el bucle descrito antes. - En un tercer terminal, observa cómo ve el broker a ese cliente:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-k7q1 -v \
-t '$SYS/broker/connection/dup-demo-k7q1/state'
En producción, una lista de comprobación rápida cuando los dispositivos se conectan y desconectan sin parar:
- Recopila los client IDs de todos los dispositivos sospechosos y busca duplicados.
- Comprueba si los reason codes de desconexión muestran 0x8E (session taken over).
- Compara los cambios de estado de conexión con las marcas de tiempo de reconexión de cada dispositivo; los patrones alternos delatan a una pareja que se disputa un ID.
- Cierra las herramientas de escritorio o sesiones de VS Code que puedan estar usando el ID de un dispositivo.
- Si las desconexiones continúan con IDs únicos, revisa en su lugar el keep alive y los timeouts de red.
Client IDs de MQTT en producción
Unos pocos hábitos operativos evitan la mayoría de los incidentes con client IDs. Genera los IDs en el momento del aprovisionamiento y no en tiempo de ejecución, para que el mismo dispositivo reciba siempre el mismo ID incluso tras un restablecimiento de fábrica. Guarda el ID junto a las credenciales del dispositivo para que el equipo de soporte pueda relacionar las entradas de log con el hardware. Cuando sustituyas una unidad averiada, decide de forma deliberada si el nuevo dispositivo hereda el ID antiguo (y su sesión) o recibe uno nuevo. En los servicios, haz que el identificador de instancia provenga de tu orquestador y no de un archivo de configuración compartido por todas las réplicas.
A medida que las flotas crecen, trata los client IDs como parte de tu proceso de aprovisionamiento: regístralos junto a los números de serie, derívalos del hardware y nunca reutilices un ID para otro dispositivo físico. Si estás aprendiendo MQTT desde cero, el tutorial de MQTT explica cómo encajan IDs, sesiones y topics.
Gestiona los client IDs de forma segura con ConnectMQ
ConnectMQ es un broker MQTT gestionado que emite un nombre de usuario, una contraseña y un client ID para cada broker que creas, y vincula los client IDs a esas credenciales para que otros tenants no puedan secuestrarlos. El estado de las conexiones se ve en directo en el portal, lo que hace que los bucles de takeover sean fáciles de detectar. Crea un broker Serverless gratuito sin tarjeta de crédito y conéctate usando YOUR_USERNAME, YOUR_PASSWORD y YOUR_CLIENT_ID.
Preguntas frecuentes
¿Qué ocurre si dos clientes MQTT usan el mismo client ID?
El broker desconecta al cliente que ya estaba conectado y se queda con el nuevo. Si ambos clientes se reconectan automáticamente, siguen expulsándose el uno al otro en un bucle.
¿Qué longitud puede tener un client ID de MQTT?
MQTT 3.1.1 garantiza soporte para entre 1 y 23 bytes de letras y dígitos, y los brokers pueden permitir IDs más largos y más caracteres. Mantener IDs cortos, alfanuméricos y con guiones es la opción más portable.
¿Debe ser aleatorio el client ID de MQTT?
Usa un ID aleatorio para clientes efímeros o intercambiables que no necesiten sesiones. Los dispositivos y servicios que dependen de sesiones persistentes necesitan un ID estable y único que no cambie entre reconexiones.
¿Es el client ID una credencial de seguridad?
No. Trátalo solo como un identificador y autentícate siempre con usuario y contraseña o con certificados; los brokers que vinculan los IDs a credenciales, como hace ConnectMQ, añaden protección contra la suplantación.



