Fundamentos de MQTT

Níveis de QoS MQTT Explicados: QoS 0, 1 e 2 com Fluxos de Pacotes e Exemplos

Um guia prático de QoS MQTT: como QoS 0, 1 e 2 funcionam na rede, por que o QoS entregue pode ser menor do que o solicitado, como as sessões enfileiram mensagens e qual nível escolher em cada caso de uso.

Diagrama dos fluxos de pacotes de QoS MQTT 0, 1 e 2 entre um cliente e um broker MQTT
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

QoS MQTT (Quality of Service) é a garantia de entrega que um cliente solicita ao publicar ou assinar. Neste guia você vai ver exatamente quais pacotes QoS 0, 1 e 2 trocam, por que o QoS que chega a um subscriber pode ser menor do que o usado na publicação, como as sessões enfileiram mensagens para clientes offline e como testar tudo isso em Python no servidor MQTT público broker.connectmq.com.

Se o MQTT em si é novidade para você, comece por O Que É um Broker MQTT? e volte aqui depois.

O Que o QoS MQTT Realmente Garante

O MQTT roda sobre TCP, então os bytes não se perdem nem chegam fora de ordem dentro de uma mesma conexão. O QoS trata de outra coisa: o que acontece quando a conexão cai no meio de uma entrega e se o receptor pode receber a mesma mensagem duas vezes.

Dois pontos costumam ser mal compreendidos:

  • O QoS é salto a salto, não ponta a ponta. O QoS do publisher rege o trecho do publisher até o broker. O QoS da assinatura rege o trecho do broker até o subscriber. O broker é o intermediário dos dois.
  • QoS mais alto não é "melhor" por padrão. Cada nível adiciona pacotes, estado e latência. A escolha certa depende de quanto custa para você uma mensagem perdida ou duplicada.
Nível Nome Garantia Pacotes por mensagem (um trecho) Pode haver duplicatas?
QoS 0 At most once Melhor esforço, sem confirmação 1 Não, mas pode haver perda
QoS 1 At least once Entregue, pode se repetir 2 Sim
QoS 2 Exactly once Entregue uma vez, sem duplicatas 4 Não

QoS 0: At Most Once

QoS 0 é "envia e esquece". O remetente escreve um pacote PUBLISH no socket e imediatamente se esquece dele. Não há packet identifier nem confirmação.

Publisher                     Broker
    |                            |
    |------ PUBLISH (QoS 0) ---->|
    |                            |   (no reply, nothing stored)

Se a conexão TCP cair enquanto o pacote ainda está em um buffer do sistema operacional, a mensagem se perde e ninguém fica sabendo. Parece ruim, mas, para uma leitura de temperatura enviada a cada dois segundos, a próxima leitura substitui a perdida de qualquer forma. O QoS 0 oferece a menor latência e o menor overhead em dispositivos com recursos limitados.

QoS 1: At Least Once

Com QoS 1, o remetente atribui um packet identifier e guarda a mensagem até o receptor responder com um PUBACK contendo o mesmo identificador.

Publisher                     Broker
    |                            |
    |-- PUBLISH (QoS 1, id=7) -->|   broker stores and forwards
    |<------- PUBACK (id=7) -----|
    |                            |   publisher deletes message 7

Se o PUBACK nunca chegar (por exemplo, porque a conexão caiu), o remetente reenvia o PUBLISH com a flag DUP ativada após reconectar. O porém: o receptor pode já ter processado a primeira cópia, e então vê a mensagem duas vezes. É por isso que QoS 1 significa pelo menos uma vez.

O QoS 1 é o burro de carga da maioria dos sistemas IoT. Torne seus consumidores idempotentes (por exemplo, inclua um ID de mensagem ou um timestamp no payload e ignore repetições) e o QoS 1 geralmente será tudo de que você precisa.

QoS 2: Exactly Once

O QoS 2 usa um handshake em quatro etapas para que os dois lados concordem que a mensagem foi entregue exatamente uma vez.

Publisher                       Broker
    |                              |
    |--- PUBLISH (QoS 2, id=9) --->|   broker stores id 9, does not forward twice
    |<------- PUBREC (id=9) -------|   "received"
    |-------- PUBREL (id=9) ------>|   "release it, I will not resend"
    |<------- PUBCOMP (id=9) ------|   "complete", both sides drop id 9

O que cada etapa faz:

  1. PUBLISH: o remetente armazena a mensagem e a envia com um packet identifier.
  2. PUBREC: o receptor registra o identificador. Se chegar um PUBLISH duplicado com o mesmo ID, ele é reconhecido e não é entregue de novo.
  3. PUBREL: o remetente descarta a mensagem e, a partir daí, só lembra do identificador.
  4. PUBCOMP: o receptor esquece o identificador. A troca termina.

O custo são duas viagens de ida e volta por mensagem e estado mantido nos dois lados até o fluxo terminar. Use QoS 2 quando uma duplicata causaria dano real e você não consegue tornar o consumidor idempotente, como um comando que incrementa um contador ou dispara um evento de cobrança.

Downgrade de QoS MQTT: Por Que Você Pode Não Receber o QoS Que Pediu

O QoS que um subscriber recebe não é simplesmente o QoS usado pelo publisher. Três números interagem.

QoS efetivo = min(QoS da publicação, QoS da assinatura)

Quando o broker encaminha uma mensagem, ele usa o menor valor entre o QoS do PUBLISH original e o QoS concedido para a assinatura.

QoS do publisher QoS da assinatura Entregue ao subscriber
0 2 0
1 2 1
2 1 1
2 0 0
2 2 2

Ou seja, se você precisa de entrega exactly-once de ponta a ponta, tanto o publisher quanto todos os subscribers precisam usar QoS 2. Uma única assinatura com QoS 0 transforma, sem alarde, o fluxo daquele subscriber em melhor esforço.

O Maximum QoS do broker (MQTT 5)

No MQTT 5, o broker pode anunciar um Maximum QoS no pacote CONNACK. Se essa propriedade não vier, o cliente pode assumir que QoS 2 é suportado. Se vier, o cliente não deve publicar acima desse nível, e o broker concederá assinaturas no máximo nesse nível (o SUBACK informa o QoS concedido).

No ConnectMQ, isso depende de onde você se conecta:

Ambiente Maximum QoS
Servidor MQTT público (broker.connectmq.com) QoS 2
Plano Serverless (Free) QoS 1
Plano Serverless (Paid) QoS 2
Dedicated, BYOC, Self Managed Enterprise QoS 2

Sempre confira o QoS concedido no SUBACK em vez de presumir. A maioria das bibliotecas cliente o expõe no callback de subscribe. A especificação do MQTT 5 em docs.oasis-open.org descreve as regras exatas. Para conhecer outras propriedades do CONNACK, veja Recursos do MQTT 5.

Sessões, Session Expiry e Fila Offline

O QoS só protege mensagens através de uma desconexão se a sessão sobreviver a essa desconexão. A sessão é o estado que o broker mantém para um cliente: suas assinaturas, as mensagens QoS 1/2 em trânsito e as mensagens enfileiradas enquanto ele está offline.

  • O MQTT 3.1.1 usa a flag Clean Session. cleanSession=true descarta a sessão na desconexão. cleanSession=false pede ao broker que a mantenha.
  • O MQTT 5 divide isso em Clean Start (começar do zero na conexão ou não) e Session Expiry Interval (por quantos segundos a sessão vive após a desconexão).

Enquanto existir uma sessão persistente e o cliente estiver offline, o broker enfileira as mensagens QoS 1 e QoS 2 que correspondem às suas assinaturas. Mensagens QoS 0 não são enfileiradas para clientes offline. Quando o cliente reconecta com o mesmo client ID e sem clean start, as mensagens enfileiradas são entregues.

Subscriber (id=sensor-reader)           Broker
    |-- CONNECT clean_start=0, expiry=600 -->|
    |-- SUBSCRIBE plant/# QoS 1 ------------>|
    |  ... connection lost ...               |
    |                                         |  PUBLISH plant/a QoS 1  -> queued
    |                                         |  PUBLISH plant/b QoS 0  -> dropped
    |-- CONNECT clean_start=0 --------------->|
    |<-- CONNACK session_present=1 -----------|
    |<-- PUBLISH plant/a ---------------------|

No ConnectMQ, o session expiry tem um teto por plano, e no servidor MQTT público as sessões vivem por até 30 minutos. Observe também que as sessões ficam em memória: elas não sobrevivem a um reinício do broker, então projete os fluxos críticos para tolerar uma reconexão com session_present=0.

Como Escolher o Nível de QoS MQTT Certo

Caso de uso QoS recomendado Por quê
Telemetria de alta frequência (temperatura, vibração) 0 A próxima amostra substitui a perdida; menor overhead
Status de dispositivo, alarmes, eventos 1 Precisa chegar; duplicatas são fáceis de ignorar
Comandos para atuadores (idempotentes: "ajustar válvula para 40%" em uma estação de saneamento) 1 Repetir o mesmo comando não causa problema
Comandos não idempotentes ("incrementar contador", "dispensar") 2 Uma duplicata mudaria o resultado
Eventos de cobrança, medição ou transações 2 (ou 1 com IDs de deduplicação) Contabilização exactly-once

Uma regra prática: use QoS 1 como padrão com consumidores idempotentes, desça para QoS 0 em dados de alta taxa que você pode se dar ao luxo de perder e reserve o QoS 2 para os poucos tipos de mensagem em que uma duplicata é um bug.

Mão na Massa: QoS 1 e QoS 2 do MQTT em Python

O script a seguir usa paho-mqtt 2.x e o servidor MQTT público broker.connectmq.com (sem usuário nem senha). Ele assina com QoS 2, publica uma mensagem com QoS 1 e outra com QoS 2 e registra as confirmações. Instale a biblioteca com pip install "paho-mqtt>=2.0".

import time
import uuid
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
UID = uuid.uuid4().hex[:8]
TOPIC = f"connectmq/demo/{UID}/qos"

def on_connect(client, userdata, flags, reason_code, properties):
    print("CONNACK:", reason_code)
    if properties is not None and hasattr(properties, "MaximumQoS"):
        print("Broker Maximum QoS:", properties.MaximumQoS)
    client.subscribe(f"{TOPIC}/#", qos=2)

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    print("SUBACK granted:", [rc.value for rc in reason_code_list])

def on_message(client, userdata, msg):
    print(f"Received {msg.topic} QoS={msg.qos} payload={msg.payload.decode()}")

def on_publish(client, userdata, mid, reason_code, properties):
    print(f"Publish flow complete for mid={mid}")

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"qos-demo-{UID}",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_publish = on_publish

client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
time.sleep(2)

client.publish(f"{TOPIC}/one", "hello at least once", qos=1).wait_for_publish()
client.publish(f"{TOPIC}/two", "hello exactly once", qos=2).wait_for_publish()

time.sleep(2)
client.loop_stop()
client.disconnect()

Com QoS 1, on_publish dispara quando o PUBACK chega. Com QoS 2, ele só dispara depois do PUBCOMP, no fim do handshake em quatro etapas. Se nenhuma linha de Maximum QoS for impressa, o broker não enviou a propriedade, o que significa que QoS 2 é permitido.

Observe os pacotes com o CLI do Mosquitto

As ferramentas de linha de comando do Eclipse Mosquitto imprimem cada pacote com -d, o que torna visíveis os fluxos acima. Em um terminal:

mosquitto_sub -h broker.connectmq.com -p 1883 -i qos-sub-a1b2 -t "connectmq/demo/a1b2/#" -q 2 -v -d

Em um segundo terminal, publique com QoS 1 e depois com QoS 2:

mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q1" -q 1 -m "hello1" -d
mosquitto_pub -h broker.connectmq.com -p 1883 -i qos-pub-a1b2 -t "connectmq/demo/a1b2/q2" -q 2 -m "hello2" -d

A saída do publisher mostra exatamente as sequências descritas antes:

Client qos-pub-a1b2 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/a1b2/q1', ... (6 bytes))
Client qos-pub-a1b2 received PUBACK (Mid: 1, RC:0)
...
Client qos-pub-a1b2 sending PUBLISH (d0, q2, r0, m1, 'connectmq/demo/a1b2/q2', ... (6 bytes))
Client qos-pub-a1b2 received PUBREC (Mid: 1)
Client qos-pub-a1b2 sending PUBREL (m1)
Client qos-pub-a1b2 received PUBCOMP (Mid: 1, RC:0)

Troque a1b2 por uma string aleatória sua. Tudo no servidor MQTT público pode ser lido por qualquer pessoa, então nunca publique dados sensíveis ali. Para experimentar downgrades, assine com -q 0 e publique com -q 2: a saída de debug do subscriber mostrará q0 no PUBLISH entregue. Mais dicas, e o lembrete de que ele serve apenas para testes e protótipos, no guia do servidor MQTT público (gratuito).

Erros Comuns com QoS

  • Presumir QoS 2 de ponta a ponta enquanto um subscriber usa QoS 0. O elo mais fraco vence.
  • Usar QoS 2 para telemetria de alta taxa. Quatro pacotes por mensagem por trecho se acumulam rápido, e a janela de mensagens em trânsito (Receive Maximum) enche.
  • Client IDs aleatórios com sessões persistentes. A fila offline só funciona se o cliente reconectar com o mesmo client ID. Um novo ID aleatório cria uma sessão nova e vazia.
  • Ignorar o QoS concedido no SUBACK. Em um plano limitado a QoS 1, uma assinatura QoS 2 é concedida como QoS 1.

Comece com o ConnectMQ

O servidor MQTT público é ótimo para aprender QoS MQTT, mas tráfego de produção, como a telemetria de uma usina ou de uma fazenda, deve ficar em um broker MQTT gerenciado privado com credenciais. Cadastre-se gratuitamente em app.connectmq.com no plano Serverless (Free), sem cartão de crédito, crie um broker e use o usuário, a senha e o client ID gerados. Faça upgrade para Serverless (Paid) ou Dedicated quando precisar de QoS 2, mais conexões ou mensagens maiores.

Perguntas frequentes

Qual é o nível de QoS MQTT padrão?

A maioria das bibliotecas cliente usa QoS 0 por padrão tanto para publish quanto para subscribe. Defina o QoS explicitamente no seu código para que o comportamento fique claro para quem o ler.

O QoS 2 deixa o MQTT mais lento?

Sim. O QoS 2 precisa de quatro pacotes e duas viagens de ida e volta por mensagem em cada trecho, contra dois pacotes no QoS 1 e um no QoS 0. Para a maior parte da telemetria, QoS 0 ou 1 oferece melhor throughput.

Por que meu subscriber recebeu QoS 1 se publiquei com QoS 2?

O QoS entregue é o mínimo entre o QoS da publicação e o QoS concedido à assinatura. Sua assinatura foi concedida com QoS 1, seja porque você pediu isso, seja porque o Maximum QoS do broker é 1, como no plano Serverless (Free) do ConnectMQ.

Mensagens QoS 0 são enfileiradas para clientes offline?

Não. Os brokers só enfileiram mensagens QoS 1 e QoS 2 para clientes com sessão persistente. Mensagens QoS 0 destinadas a um cliente offline são descartadas.

Posso usar QoS 2 no broker.connectmq.com?

Sim. O servidor MQTT público, de acesso anônimo, suporta QoS 0, 1 e 2. Brokers privados suportam QoS 2 no Serverless (Paid) e nos planos superiores, enquanto o plano Serverless (Free) é limitado a QoS 1.

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.