O client ID MQTT é o identificador que um cliente envia no CONNECT, e o broker o usa para distinguir conexões e sessões. Este guia explica por que dois clientes com o mesmo ID ficam desconectando um ao outro, como projetar formatos de ID que escalem de um protótipo a uma frota inteira e como diagnosticar takeovers rapidamente ao testar no servidor MQTT público.
Para Que Serve o Client ID MQTT
Todo pacote CONNECT carrega um campo Client Identifier. O broker MQTT o usa para três coisas:
- Unicidade da conexão. Só uma conexão de rede por client ID pode estar ativa de cada vez.
- Localização da sessão. O estado da sessão persistente (assinaturas e mensagens enfileiradas) é armazenado sob o client ID.
- Operação. Logs, eventos de conexão e topics de monitoramento se referem aos clientes pelo ID.
Ele não é, por si só, uma credencial de autenticação. Qualquer um que consiga se conectar pode reivindicar qualquer ID, a menos que o broker vincule os IDs às credenciais. Nos brokers privados da ConnectMQ, os client IDs ficam vinculados às credenciais emitidas no portal, então outro usuário não pode reutilizar o ID do seu dispositivo.
Por Que Client IDs Duplicados Derrubam Uns aos Outros
A especificação é explícita: se um cliente se conecta com um ID que já está conectado, o broker deve desconectar o cliente existente. Isso se chama session takeover. Existe para que um dispositivo que perdeu a conexão silenciosamente possa se reconectar na hora, sem esperar o socket antigo expirar.
O problema aparece quando dois clientes diferentes compartilham um ID. A sequência é esta:
- O cliente A se conecta como
sensor-01. - O cliente B se conecta como
sensor-01. O broker desconecta A. - A reconexão automática de A dispara e ele se conecta como
sensor-01. O broker desconecta B. - B se reconecta... e o ciclo se repete a cada poucos segundos.
Os sintomas incluem logs constantes de conexão e desconexão, mensagens perdidas, mensagens de will disparadas repetidamente e um indicador "online/offline" que fica piscando. No MQTT 5, o cliente derrubado recebe um DISCONNECT com o reason code 0x8E (Session taken over), o que torna o diagnóstico muito mais fácil do que no 3.1.1, em que o socket simplesmente fecha.
Causas Comuns
- A mesma imagem de firmware gravada em várias placas com um ID fixo no código.
- Código de exemplo copiado e colado com um ID como
testouesp32client. - Um serviço rodando em vários containers ou pods com o mesmo ID configurado.
- Um desenvolvedor rodando o mesmo script em dois terminais.
- Uma ferramenta MQTT de desktop e um dispositivo usando ambos o ID do dispositivo.
Projetando um Formato de Client ID MQTT
Bons IDs são únicos, estáveis, legíveis e seguros para qualquer broker.
Regras de Formato
| Regra | Por quê |
|---|---|
Use apenas a-z, A-Z, 0-9, - e _ |
Todo broker é obrigado a aceitar esses caracteres |
| Mantenha curto, de preferência com 23 caracteres ou menos | O MQTT 3.1.1 só garante suporte até 23 bytes; a maioria dos brokers permite mais |
| Nunca deixe vazio em produção | IDs vazios impedem sessões persistentes, e muitos brokers os rejeitam |
| Mantenha estável em dispositivos com sessões | Um ID que muda significa uma nova sessão a cada vez |
| Torne único por instância em execução | Evita loops de takeover |
| Evite segredos e dados pessoais | Os IDs aparecem em logs e no monitoramento |
Padrões Que Funcionam
- Dispositivos: um prefixo mais um identificador derivado do hardware, como
env-mais os últimos bytes do endereço MAC (env-a4cf12b3), ou um número de série do seu banco de dados de fabricação. - Serviços de backend: nome do serviço mais identificador da instância, como
alarm-worker-0a partir do ordinal de um StatefulSet. Se as instâncias forem totalmente intercambiáveis e não precisarem de sessões, um sufixo aleatório é suficiente. - Dashboards no navegador: um prefixo mais uma string aleatória por aba, com sessões limpas, porque ninguém precisa retomar a sessão de um dashboard.
- Scripts de teste: um sufixo aleatório a cada execução, por exemplo
test-mais 6 caracteres hexadecimais aleatórios.
Gerando IDs no Código
Python, usando o endereço MAC para um ID de dispositivo estável ou um token aleatório para clientes de teste:
import secrets
import uuid
import paho.mqtt.client as mqtt
def device_client_id(prefix: str = "env") -> str:
mac = uuid.getnode() # endereço de hardware de 48 bits como int
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)
ESP32 com PubSubClient, derivando o ID do MAC gravado no 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);
}
}
}
A configuração completa da placa, incluindo o Wi-Fi, está no tutorial de MQTT com ESP32.
Client IDs Vazios e Identificadores Atribuídos
O MQTT 3.1.1 permite um client ID de tamanho zero apenas com clean session igual a true; nesse caso, o broker inventa um internamente. O MQTT 5 vai além: o broker retorna um Assigned Client Identifier no CONNACK para que o cliente saiba o seu nome. Isso é prático para clientes descartáveis, mas impede o uso de sessões persistentes, porque você não consegue se reconectar com uma identidade que não controla. Muitos brokers, incluindo o servidor MQTT público da ConnectMQ, simplesmente exigem um ID não vazio, o que de qualquer forma é o hábito mais seguro.
Como Detectar um Takeover de Client ID
Aqui está um teste reproduzível no servidor MQTT público (gratuito). Use o seu próprio sufixo aleatório e lembre-se de que a área pública pode ser lida por qualquer pessoa e serve para testes e protótipos, não para dados de produção.
- No primeiro terminal, conecte-se com um ID e saída de depuração:
mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
-i dup-demo-k7q1 -d -t 'connectmq/demo/k7q1/#'
- No segundo terminal, execute exatamente o mesmo comando.
- O primeiro terminal é desconectado imediatamente; com
-dvocê vê o broker fechar a conexão. Dependendo da versão do mosquitto, ele encerra ou reconecta e, nesse caso, os dois terminais começam a derrubar um ao outro, que é exatamente o loop descrito acima. - Em um terceiro terminal, acompanhe a visão do broker sobre esse cliente:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-k7q1 -v \
-t '$SYS/broker/connection/dup-demo-k7q1/state'
Em produção, um checklist rápido quando os dispositivos ficam caindo e voltando:
- Colete os client IDs de todos os dispositivos suspeitos e procure duplicatas.
- Verifique se os reason codes de desconexão mostram 0x8E (session taken over).
- Compare as mudanças de estado da conexão com os timestamps de reconexão de cada dispositivo; padrões alternados revelam um par disputando um único ID.
- Feche ferramentas de desktop ou sessões do VS Code que possam estar usando o ID de um dispositivo.
- Se as quedas continuarem com IDs únicos, investigue keep alive e timeouts de rede.
Client IDs MQTT em Produção
Alguns hábitos operacionais evitam a maioria dos incidentes com client IDs. Gere os IDs no provisionamento, e não em tempo de execução, para que o mesmo dispositivo receba sempre o mesmo ID, mesmo após um reset de fábrica. Guarde o ID junto às credenciais do dispositivo para que a equipe de suporte consiga associar entradas de log ao hardware. Ao substituir uma unidade com defeito, decida conscientemente se o novo dispositivo herda o ID antigo (e a sessão dele) ou recebe um novo. Em serviços, faça o identificador da instância vir do seu orquestrador, e não de um arquivo de configuração compartilhado por todas as réplicas.
À medida que as frotas crescem, trate os client IDs como parte do seu processo de provisionamento: registre-os junto aos números de série, derive-os do hardware e nunca reutilize um ID para um dispositivo físico diferente. Se você está aprendendo MQTT do zero, o tutorial de MQTT explica como IDs, sessões e topics se encaixam.
Gerencie Client IDs com Segurança na ConnectMQ
A ConnectMQ é um broker MQTT gerenciado que emite usuário, senha e client ID para cada broker que você cria e vincula os client IDs a essas credenciais, para que outros tenants não possam sequestrá-los. O estado das conexões fica visível ao vivo no portal, o que facilita identificar loops de takeover. Crie um broker Serverless gratuito sem cartão de crédito e conecte-se usando YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID.
Perguntas frequentes
O que acontece se dois clientes MQTT usarem o mesmo client ID?
O broker desconecta o cliente que já estava conectado e mantém o novo. Se ambos os clientes tiverem reconexão automática, eles ficam derrubando um ao outro em loop.
Qual pode ser o tamanho de um client ID MQTT?
O MQTT 3.1.1 garante suporte de 1 a 23 bytes de letras e dígitos, e os brokers podem permitir IDs mais longos e mais caracteres. Manter os IDs curtos e alfanuméricos com hifens é a escolha mais portável.
O client ID MQTT deve ser aleatório?
Use um ID aleatório para clientes de curta duração ou intercambiáveis que não precisam de sessões. Dispositivos e serviços que dependem de sessões persistentes precisam de um ID estável e único, que permaneça o mesmo entre reconexões.
O client ID é uma credencial de segurança?
Não. Trate-o apenas como identificador e sempre autentique com usuário e senha ou certificados; brokers que vinculam IDs a credenciais, como a ConnectMQ, adicionam proteção contra falsificação de identidade.



