Fundamentos de MQTT

Boas Práticas de Client ID MQTT: Unicidade, Formato e Takeovers

O client ID é como um broker MQTT sabe quem você é. Erre nele e os dispositivos derrubam uns aos outros ou perdem suas sessões. Veja as regras, os formatos e os passos de depuração que funcionam.

Ilustração de client ID MQTT mostrando dois dispositivos com o mesmo identificador disputando uma única conexão com o broker
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

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:

  1. Unicidade da conexão. Só uma conexão de rede por client ID pode estar ativa de cada vez.
  2. Localização da sessão. O estado da sessão persistente (assinaturas e mensagens enfileiradas) é armazenado sob o client ID.
  3. 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:

  1. O cliente A se conecta como sensor-01.
  2. O cliente B se conecta como sensor-01. O broker desconecta A.
  3. A reconexão automática de A dispara e ele se conecta como sensor-01. O broker desconecta B.
  4. 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 test ou esp32client.
  • 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-0 a 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.

  1. 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/#'
  1. No segundo terminal, execute exatamente o mesmo comando.
  2. O primeiro terminal é desconectado imediatamente; com -d você 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.
  3. 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:

  1. Colete os client IDs de todos os dispositivos suspeitos e procure duplicatas.
  2. Verifique se os reason codes de desconexão mostram 0x8E (session taken over).
  3. 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.
  4. Feche ferramentas de desktop ou sessões do VS Code que possam estar usando o ID de um dispositivo.
  5. 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.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.