Os tópicos SYS do MQTT formam o ramo $SYS/... da árvore de topics, onde o broker publica informações sobre si mesmo em vez de dados da aplicação. Neste artigo você vai aprender de onde vem essa convenção, por que uma assinatura simples em # nunca os mostra, o que um broker típico expõe ali e como usar o único topic de sistema que o ConnectMQ publica para acompanhar o estado de conexão dos clientes.
O que são os tópicos SYS do MQTT?
A especificação MQTT reserva os topics que começam com $ para uso específico do broker. Os clientes não devem publicar dados da aplicação neles, e a especificação deixa o conteúdo totalmente a cargo da implementação. Com o passar dos anos, $SYS/ virou o prefixo de fato para a telemetria do broker: tempo de atividade, versão, número de clientes conectados, contadores de mensagens e bytes e dados administrativos semelhantes.
A expressão importante é "de fato". Não existe uma lista padrão de topics $SYS, nem um formato padrão de payload, nem garantia de que um determinado broker publique algum deles. O Mosquitto popularizou uma árvore grande, outros brokers publicam um subconjunto ou um layout diferente, e muitos brokers MQTT gerenciados substituem a maior parte disso por dashboards e APIs. Trate cada topic $SYS como um detalhe de implementação do broker específico ao qual você está conectado.
Por que uma assinatura em # não os mostra
Isso surpreende quase todo mundo na primeira vez. Se você se inscreve em #, recebe todas as mensagens de aplicação do broker, mas nada de $SYS. Isso é proposital. A especificação MQTT no mqtt.org determina que um filtro de topic que começa com curinga (# ou +) não deve corresponder a nomes de topic que começam com $.
A regra protege os assinantes "pega-tudo" comuns de serem inundados com estatísticas do broker e evita que ferramentas que espelham # republiquem dados de sistema por acidente. Para ler os topics de sistema, você precisa indicar o prefixo $SYS explicitamente:
# -> application topics only, never $SYS
$SYS/# -> everything under $SYS (if the broker allows it)
$SYS/broker/+/+ -> a specific depth under $SYS/broker
+/broker/uptime -> does NOT match $SYS/broker/uptime
O mesmo raciocínio vale para as regras de curingas dos topics MQTT em geral: os curingas funcionam nível a nível, e o nível inicial com $ simplesmente fica de fora da correspondência por curinga na primeira posição.
Uma árvore $SYS típica (exemplo com Mosquitto)
O Mosquitto é a referência mais comum, então é uma boa forma de ver o que os topics de sistema podem conter. Com a configuração padrão, ele publica um instantâneo dos seus contadores a cada poucos segundos. O intervalo é controlado no mosquitto.conf:
# mosquitto.conf
# Publica atualizações $SYS a cada 10 segundos (0 desativa as atualizações periódicas)
sys_interval 10
Uma seleção dos topics que você verá em uma instância local do Mosquitto:
| Topic | Significado |
|---|---|
$SYS/broker/version |
String de versão do broker |
$SYS/broker/uptime |
Segundos desde que o broker iniciou |
$SYS/broker/clients/connected |
Clientes conectados no momento |
$SYS/broker/clients/disconnected |
Sessões persistentes cujo cliente está offline |
$SYS/broker/messages/received |
Total de mensagens recebidas desde o início |
$SYS/broker/messages/sent |
Total de mensagens enviadas desde o início |
$SYS/broker/subscriptions/count |
Assinaturas ativas |
$SYS/broker/retained messages/count |
Retained messages armazenadas |
$SYS/broker/load/messages/received/1min |
Média móvel de mensagens recebidas |
$SYS/broker/bytes/received |
Total de bytes recebidos |
Para acompanhá-los no seu próprio broker Mosquitto, coloque o topic entre aspas para que o shell não expanda $SYS:
mosquitto_sub -h localhost -p 1883 -i sys-watcher-01 -t '$SYS/#' -v
A maioria dos valores é publicada como retained message, então um novo assinante recebe o instantâneo mais recente imediatamente, em vez de esperar o próximo intervalo. Os contadores são zerados quando o broker reinicia, o que importa se você os coloca em gráfico: uma queda para zero significa uma reinicialização, não uma hora tranquila.
Armadilhas comuns com dados $SYS
- Presumir portabilidade. Um dashboard construído sobre os topics
$SYSdo Mosquitto quebra no momento em que você migra para outro broker. Mantenha a lógica de parsing em um único lugar. - Esquecer o shell. No bash,
"$SYS/#"com aspas duplas expande$SYSpara uma variável vazia e você acaba se inscrevendo em/#. Use aspas simples. - Expor publicamente. Em um broker auto-hospedado, os topics de sistema revelam o número de clientes e as versões. Restrinja-os com as regras de autorização do broker se ele for acessível pela internet.
- Consultar rápido demais. Um
sys_intervalmuito curto adiciona tráfego com pouco valor. De dez a sessenta segundos é mais do que suficiente para gráficos operacionais.
Tópicos SYS do MQTT em um broker gerenciado
Em um broker MQTT gerenciado, normalmente você não precisa de uma árvore $SYS grande, porque o operador já coleta as métricas do broker e as mostra para você. Essa é a abordagem do ConnectMQ. Informações no nível do broker, como conexões e tráfego, são apresentadas no dashboard do portal, e o explorador de topics ao vivo permite ver quais topics estão ativos, então não é preciso fazer parsing de contadores a partir de topics de sistema.
Ele publica exatamente um topic de sistema:
$SYS/broker/connection/{clientId}/state
Esse topic informa o estado de conexão de um client ID específico. É a parte dos dados $SYS de que o código da aplicação realmente precisa: "o dispositivo X está online agora?" Todo o resto, como contagem de clientes e taxas de mensagens, pertence ao monitoramento, e não ao seu fluxo de dados MQTT.
Acompanhando o estado de conexão de um cliente
O exemplo abaixo usa o paho-mqtt 2.x em Python para se inscrever no topic de estado de um dispositivo no seu broker privado. Substitua os placeholders pelas credenciais geradas no portal e defina DEVICE_ID com o client ID do dispositivo que você quer acompanhar.
import ssl
import paho.mqtt.client as mqtt
BROKER = "YOUR_BROKER_HOST" # exibido no portal
PORT = 8883
DEVICE_ID = "YOUR_DEVICE_CLIENT_ID"
STATE_TOPIC = f"$SYS/broker/connection/{DEVICE_ID}/state"
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"Connect failed: {reason_code}")
return
print("Connected, subscribing to", STATE_TOPIC)
client.subscribe(STATE_TOPIC, qos=1)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
for rc in reason_code_list:
print("SUBACK:", rc)
def on_message(client, userdata, msg):
print(f"{msg.topic} -> {msg.payload.decode(errors='replace')}")
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id="YOUR_CLIENT_ID",
protocol=mqtt.MQTTv5,
)
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=60)
client.loop_forever()
Execute o script e depois desligue e religue o dispositivo ou pare o cliente dele. Você verá o topic de estado mudar conforme o dispositivo se desconecta e se reconecta. Antes de escrever a lógica de parsing, observe o payload real no cliente MQTT do portal, que roda no navegador, para que o seu código corresponda ao que o broker envia e não ao que você imagina.
Estado $SYS versus Last Will
Talvez você já acompanhe a presença com uma mensagem de Last Will and Testament. As duas abordagens se complementam:
| Abordagem | Quem publica | Ponto forte | Limitação |
|---|---|---|---|
| Last Will mais mensagem retida "online" | O dispositivo e o broker em nome dele | Funciona em qualquer broker; topic e payload são seus | O dispositivo precisa configurá-la corretamente; um cliente mal configurado nunca informa nada |
$SYS/broker/connection/{clientId}/state |
O broker | Não exige código no dispositivo; reflete o que o broker realmente vê | Layout de topic específico do broker |
Um padrão sensato é manter o Last Will para consumidores da aplicação que já entendem a sua árvore de topics e usar o topic de estado do broker para ferramentas de operação e para verificar se dispositivos sem Will estão se comportando bem. O guia sobre status online de dispositivos MQTT detalha o padrão baseado em Will.
Checklist de monitoramento sem uma grande árvore $SYS
Se você vem de um broker auto-hospedado em que os gráficos do Grafana eram alimentados por $SYS, veja como cobrir as mesmas necessidades em um broker MQTT gerenciado:
- Contagem de conexões e tráfego. Use o dashboard do broker no portal em vez de
$SYS/broker/clients/connected. - Quais topics estão vivos. Use o explorador de topics ao vivo em vez de se inscrever em
#a partir de um notebook. - Presença por dispositivo. Inscreva-se em
$SYS/broker/connection/{clientId}/statepara os client IDs que interessam, ou use um Last Will. - Condições de limite sobre os dados. Configure regras de alerta no portal para valores como temperatura ou pressão e revise o log de alertas.
- Histórico de métricas de longo prazo. Execute seu próprio assinante (Telegraf, um pequeno serviço em Python ou Node-RED) que grave os dados necessários no seu banco de séries temporais.
- Atenção às cotas. Fique de olho no reason code
0x97(quota exceeded) do MQTT 5 nos logs dos clientes; ele indica que um limite do plano foi atingido.
Testando no servidor MQTT público
Se você só quer experimentar a estrutura de topics, o servidor MQTT público (gratuito) em broker.connectmq.com aceita conexões anônimas com qualquer client ID único e não vazio. Lembre-se de que a área pública pode ser lida por todos, então use um prefixo único e nunca envie dados sensíveis ou de produção:
# Terminal 1: inscreva-se no seu próprio prefixo de demonstração
mosquitto_sub -h broker.connectmq.com -p 1883 -i sys-demo-sub-7f3a \
-t 'connectmq/demo/7f3a/#' -v
# Terminal 2: publique uma mensagem de teste
mosquitto_pub -h broker.connectmq.com -p 1883 -i sys-demo-pub-7f3a \
-t 'connectmq/demo/7f3a/hello' -m 'hi'
Repare que a assinatura # no terminal 1 vê a sua mensagem, mas nada sob $SYS, exatamente como a especificação exige. Para uma visão mais ampla de como topics, assinaturas e o broker se encaixam, o tutorial de MQTT é uma boa próxima leitura, e as convenções de nomenclatura de topics MQTT mostram como manter a sua própria árvore tão organizada quanto a árvore de sistema de um broker.
Comece a usar o ConnectMQ
Quer métricas do broker sem fazer parsing de contadores $SYS? Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito. Em poucos minutos você recebe credenciais geradas, um dashboard, um explorador de topics ao vivo e o topic $SYS/broker/connection/{clientId}/state para presença por dispositivo.
Perguntas frequentes
Por que a assinatura em # não mostra as mensagens $SYS?
A especificação MQTT diz que filtros de topic que começam com curinga não devem corresponder a topics que começam com $. Inscreva-se explicitamente em $SYS/# se o seu broker publicar topics de sistema e permitir que você os leia.
Os tópicos SYS do MQTT são padronizados?
Não. Apenas a reserva dos topics com prefixo $ é padronizada. Os nomes dos topics, os payloads e os intervalos de atualização variam entre brokers, então o código que os lê é específico do broker.
Qual topic $SYS o ConnectMQ publica?
O ConnectMQ publica $SYS/broker/connection/{clientId}/state, que informa o estado de conexão de um cliente. Métricas do broker, como conexões e tráfego, são mostradas no dashboard do portal.
Posso publicar minhas próprias mensagens em topics $SYS?
Não deveria. O prefixo $ é reservado para o broker, e a maioria dos brokers rejeita ou ignora publicações de clientes ali. Coloque seus próprios dados de status na árvore de topics da sua aplicação.



