Escolher entre bibliotecas cliente MQTT é a primeira decisão de engenharia de verdade em qualquer projeto MQTT, e uma escolha errada aparece mais tarde na forma de bugs de reconexão, recursos do MQTT 5 ausentes ou um event loop bloqueado. Este guia compara as opções mantidas para Python, JavaScript, Go, Java, C#, Rust, C, microcontroladores e mobile, e traz para cada uma um exemplo mínimo que se conecta ao broker.connectmq.com, o servidor MQTT público (gratuito) do ConnectMQ. Ao final, você saberá qual biblioteca combina com a sua stack e o que verificar antes de se comprometer com ela.
O Que uma Biblioteca Cliente MQTT Faz de Fato
Uma biblioteca cliente MQTT esconde o protocolo binário atrás de poucas chamadas: connect, subscribe, publish, disconnect. Por baixo dos panos ela faz muito mais, e é nessas tarefas ocultas que as bibliotecas se diferenciam:
- Codificação e decodificação de pacotes para MQTT 3.1.1 e, nas bibliotecas melhores, propriedades do MQTT 5.0 como reason codes, expiração de mensagens e user properties.
- Pings de keep-alive para que o broker saiba que a conexão está saudável.
- Máquinas de estado de QoS que armazenam mensagens QoS 1 e QoS 2 em trânsito e as reenviam após uma reconexão.
- Lógica de reconexão com backoff, além de reassinar os topics quando a sessão não foi persistida.
- Tratamento de transporte para TCP, TLS e WebSocket.
- Integração com threads ou async no seu runtime: uma thread em segundo plano, um event loop, goroutines ou callbacks.
Uma biblioteca que acerta a codificação do protocolo mas lida mal com reconexões passa em todas as demos e falha em campo, por exemplo no gateway celular de uma fazenda ou de uma mineradora. Tenha isso em mente ao ler a comparação abaixo. Se o lado do broker ainda não estiver claro, leia primeiro o que um broker MQTT faz; todas as bibliotecas aqui são apenas clientes de um broker.
Como Avaliar Bibliotecas Cliente MQTT
Use este checklist antes de adotar qualquer biblioteca, seja qual for a linguagem:
- Manutenção. Observe os lançamentos recentes e como as issues são tratadas. O MQTT em si é estável, mas stacks de TLS, runtimes e plataformas mudam o tempo todo.
- Versão do protocolo. Você precisa de MQTT 5? Assinaturas compartilhadas, expiração de mensagens, request/response e reason codes detalhados só existem nele.
- Transportes. Navegadores precisam de WebSocket; redes corporativas restritas muitas vezes exigem WSS em portas no estilo da 443; dispositivos geralmente usam TLS na 8883.
- Modelo de concorrência. Baseado em callbacks, em threads ou em async/await. Escolha o que combina com o resto do seu código, não o que parece mais curto em um README.
- Reconexão e buffer offline. Ela reconecta automaticamente? Enfileira publishes enquanto está offline, e essa fila tem limite?
- Persistência de mensagens em trânsito. Só em memória ou em arquivo? Isso importa para QoS 1 e 2 entre reinícios do processo.
- Footprint. Em microcontroladores, RAM e flash decidem tudo; em servidores, raramente importam.
- Licença. As bibliotecas mais populares usam EPL/EDL, MIT ou Apache 2.0, mas confira antes de lançar um produto comercial.
Bibliotecas Cliente MQTT em Resumo
| Linguagem / plataforma | Biblioteca | MQTT 5 | Modelo | Indicada para |
|---|---|---|---|---|
| Python | paho-mqtt 2.x | Sim | Thread em segundo plano ou loop manual | Scripts, gateways, Raspberry Pi |
| Python | aiomqtt | Sim | asyncio | Serviços assíncronos, backends FastAPI |
| JavaScript / TypeScript | MQTT.js 5.x | Sim | Event emitter, promises | Node.js e navegadores (WebSocket) |
| Go | Eclipse Paho Go (paho.mqtt.golang) | Não (3.1.1) | Tokens, goroutines | Serviços 3.1.1 maduros |
| Go | Eclipse Paho paho.golang | Sim | Baseado em context | Novos serviços MQTT 5 |
| Java / Kotlin | Eclipse Paho Java (mqttv3, mqttv5) | Sim (pacote v5) | Clientes síncronos e assíncronos | Backends JVM, Android |
| Java / Kotlin | HiveMQ MQTT Client | Sim | Bloqueante, assíncrono, reativo | Stacks JVM reativas |
| C# / .NET | MQTTnet | Sim | async/await | ASP.NET Core, MAUI, Unity |
| Rust | rumqttc | Sim | async (tokio) ou síncrono | Serviços de borda, gateways |
| C | Eclipse Paho C, libmosquitto | Sim | Síncrono e assíncrono | Dispositivos Linux, aplicações nativas |
| Arduino / ESP32 | PubSubClient, AsyncMqttClient | Não (3.1.1) | Baseado em loop / callbacks assíncronos | Microcontroladores |
| ESP-IDF | esp-mqtt | Sim | Event handler | Firmware ESP32 de produção |
| Swift | CocoaMQTT | Sim | Delegate / closures | Apps iOS e macOS |
| Dart / Flutter | mqtt_client | Não (3.1.1) | Streams | Mobile multiplataforma |
A tabela reflete os recursos documentados das bibliotecas no momento em que este texto foi escrito. Sempre confirme nas notas de versão atuais de cada projeto, porque o suporte a MQTT 5, em especial, vem chegando em etapas. A página do projeto Eclipse Paho em eclipse.dev/paho é um bom ponto de partida para a família Paho.
Python: paho-mqtt e aiomqtt
O paho-mqtt é a escolha padrão em Python e funciona em quase todo lugar, de um Raspberry Pi a um contêiner. A versão 2.x introduziu uma mudança incompatível: é obrigatório informar uma versão da API de callbacks, e os callbacks v2 recebem reason codes e properties. A maioria dos relatos de "não funciona" vem de copiar exemplos 1.x para uma instalação 2.x, o que é explicado em detalhes em a correção do CallbackAPIVersion no paho-mqtt 2.0.
import uuid
import paho.mqtt.client as mqtt
TOPIC = "connectmq/demo/k3x8p1/libs/python"
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe(TOPIC, qos=1)
client.publish(TOPIC, "hello from paho-mqtt", qos=1)
def on_message(client, userdata, msg):
print(msg.topic, msg.payload.decode())
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id=f"libs-py-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_message = on_message
client.tls_set()
client.connect("broker.connectmq.com", 8883, keepalive=30)
client.loop_forever()
O aiomqtt encapsula o paho em uma API asyncio idiomática com async with e async for. Se o seu serviço já roda um event loop, use-o em vez de misturar threads e corrotinas. Os passo a passo completos estão no nosso tutorial de paho-mqtt em Python e no guia de aiomqtt com asyncio.
JavaScript e TypeScript: MQTT.js
O MQTT.js é a biblioteca de fato para Node.js e para o navegador, traz tipos TypeScript e suporta MQTT 5. No Node.js ele se conecta via TCP ou TLS; no navegador usa WebSocket, então o esquema da URL é a única coisa que muda.
import mqtt from "mqtt";
const clientId = "libs-js-" + Math.random().toString(16).slice(2, 10);
const topic = "connectmq/demo/k3x8p1/libs/javascript";
// Node.js: mqtts://broker.connectmq.com:8883
// Navegador: wss://broker.connectmq.com:8084/mqtt
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId,
protocolVersion: 5,
});
client.on("connect", async () => {
await client.subscribeAsync(topic, { qos: 1 });
await client.publishAsync(topic, "hello from MQTT.js", { qos: 1 });
});
client.on("message", (t, payload) => console.log(t, payload.toString()));
client.on("error", (err) => console.error(err.message));
O MQTT.js reconecta automaticamente por padrão (reconnectPeriod controla o intervalo). No navegador, lembre-se de que uma página HTTPS só pode abrir conexões wss://. Padrões específicos de frameworks estão em MQTT.js com Node.js e MQTT no navegador com JavaScript.
Go: Eclipse Paho
Go tem dois projetos Eclipse. O paho.mqtt.golang é o cliente MQTT 3.1.1 consolidado, usado em muitíssimos serviços de produção. O paho.golang é a implementação mais nova de MQTT 5, com um pacote autopaho que gerencia a reconexão para você. Para um novo projeto MQTT 5, comece pelo paho.golang; para ampla compatibilidade com 3.1.1 e a maior base de exemplos, o cliente clássico continua sendo uma escolha sólida.
package main
import (
"crypto/tls"
"fmt"
"math/rand"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
func main() {
topic := "connectmq/demo/k3x8p1/libs/go"
opts := mqtt.NewClientOptions().
AddBroker("tls://broker.connectmq.com:8883").
SetClientID(fmt.Sprintf("libs-go-%06d", rand.Intn(1000000))).
SetTLSConfig(&tls.Config{MinVersion: tls.VersionTLS12}).
SetAutoReconnect(true)
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
client.Subscribe(topic, 1, func(_ mqtt.Client, m mqtt.Message) {
fmt.Printf("%s %s\n", m.Topic(), m.Payload())
}).Wait()
client.Publish(topic, 1, false, "hello from Go").Wait()
time.Sleep(2 * time.Second)
client.Disconnect(250)
}
Veja como construir um cliente MQTT em Go para encerramento gracioso e payloads estruturados.
Java e Kotlin: Paho e HiveMQ Client
O Eclipse Paho Java oferece dois pacotes: org.eclipse.paho.client.mqttv3 para MQTT 3.1.1 e org.eclipse.paho.mqttv5.client para MQTT 5. O HiveMQ MQTT Client é uma alternativa com APIs bloqueante, assíncrona e reativa, que se encaixa bem em bases de código com Reactor ou RxJava. Ambos também rodam no Android, e é por isso que apps Kotlin costumam usá-los diretamente.
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.util.UUID;
public class LibsJava {
public static void main(String[] args) throws Exception {
String topic = "connectmq/demo/k3x8p1/libs/java";
String clientId = "libs-java-" + UUID.randomUUID().toString().substring(0, 8);
MqttClient client = new MqttClient("ssl://broker.connectmq.com:8883",
clientId, new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
client.connect(options);
client.subscribe(topic, 1, (t, msg) ->
System.out.println(t + " " + new String(msg.getPayload())));
client.publish(topic, "hello from Paho Java".getBytes(), 1, false);
Thread.sleep(2000);
client.disconnect();
client.close();
}
}
Quem usa Spring Boot normalmente encapsula isso no Spring Integration; os padrões estão no nosso guia de cliente MQTT em Java e no tutorial de MQTT no Android com Kotlin.
C# e .NET: MQTTnet
O MQTTnet é a biblioteca padrão do .NET e suporta MQTT 5, TLS e WebSocket. É totalmente assíncrono e se encaixa em hosted services do ASP.NET Core, apps .NET MAUI e Unity. Atenção às diferenças entre as versões principais: a versão 5 renomeou a factory para MqttClientFactory, enquanto a versão 4 usa MqttFactory. O exemplo é para a versão 5.
using MQTTnet;
using MQTTnet.Formatter;
var topic = "connectmq/demo/k3x8p1/libs/csharp";
var factory = new MqttClientFactory();
using var client = factory.CreateMqttClient();
client.ApplicationMessageReceivedAsync += e =>
{
Console.WriteLine($"{e.ApplicationMessage.Topic} {e.ApplicationMessage.ConvertPayloadToString()}");
return Task.CompletedTask;
};
var options = new MqttClientOptionsBuilder()
.WithTcpServer("broker.connectmq.com", 8883)
.WithClientId($"libs-cs-{Guid.NewGuid():N}"[..16])
.WithProtocolVersion(MqttProtocolVersion.V500)
.WithTlsOptions(o => o.UseTls())
.Build();
await client.ConnectAsync(options);
await client.SubscribeAsync(factory.CreateSubscribeOptionsBuilder()
.WithTopicFilter(topic).Build());
await client.PublishAsync(new MqttApplicationMessageBuilder()
.WithTopic(topic).WithPayload("hello from MQTTnet").Build());
await Task.Delay(2000);
await client.DisconnectAsync();
O cliente de baixo nível do MQTTnet não reconecta sozinho, então envolva a conexão em um loop ou em um background service. O tutorial de MQTTnet mostra um padrão resiliente com hosted service.
Rust: rumqttc
O rumqttc é o cliente Rust mais usado. Ele separa o handle do cliente de um event loop que você consulta (poll), o que dá controle explícito sobre back-pressure. Existem módulos tanto para MQTT 3.1.1 quanto para MQTT 5.
use rumqttc::{AsyncClient, Event, MqttOptions, Packet, QoS};
use std::time::Duration;
#[tokio::main]
async fn main() {
let topic = "connectmq/demo/k3x8p1/libs/rust";
let mut opts = MqttOptions::new("libs-rust-k3x8p1", "broker.connectmq.com", 1883);
opts.set_keep_alive(Duration::from_secs(30));
let (client, mut eventloop) = AsyncClient::new(opts, 10);
client.subscribe(topic, QoS::AtLeastOnce).await.unwrap();
client.publish(topic, QoS::AtLeastOnce, false, "hello from rumqttc").await.unwrap();
loop {
match eventloop.poll().await {
Ok(Event::Incoming(Packet::Publish(p))) => {
println!("{} {}", p.topic, String::from_utf8_lossy(&p.payload));
}
Ok(_) => {}
Err(e) => {
eprintln!("connection error: {e}");
tokio::time::sleep(Duration::from_secs(2)).await;
}
}
}
}
Chamar o poll do event loop de novo após um erro é a forma como o rumqttc reconecta. O TLS exige uma das suas feature flags de TLS; o guia de rumqttc cobre essa configuração.
C e Sistemas Embarcados: Paho C, libmosquitto, PubSubClient, esp-mqtt
Para aplicações Linux nativas, o Eclipse Paho C oferece APIs síncronas e assíncronas com suporte a MQTT 5, e a libmosquitto é uma alternativa pequena e testada em batalha do projeto Mosquitto.
#include <stdio.h>
#include <string.h>
#include "MQTTClient.h"
int main(void) {
MQTTClient client;
MQTTClient_connectOptions opts = MQTTClient_connectOptions_initializer;
MQTTClient_message msg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
const char *topic = "connectmq/demo/k3x8p1/libs/c";
char payload[] = "hello from Paho C";
MQTTClient_create(&client, "tcp://broker.connectmq.com:1883", "libs-c-k3x8p1",
MQTTCLIENT_PERSISTENCE_NONE, NULL);
opts.keepAliveInterval = 30;
opts.cleansession = 1;
if (MQTTClient_connect(client, &opts) != MQTTCLIENT_SUCCESS) {
fprintf(stderr, "connect failed\n");
return 1;
}
msg.payload = payload;
msg.payloadlen = (int)strlen(payload);
msg.qos = 1;
msg.retained = 0;
MQTTClient_publishMessage(client, topic, &msg, &token);
MQTTClient_waitForCompletion(client, token, 10000L);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return 0;
}
Em microcontroladores, os trade-offs mudam. O PubSubClient é minúsculo e simples, mas suporta apenas MQTT 3.1.1, publica em QoS 0 e tem um buffer de pacotes padrão de 256 bytes que você precisa aumentar com setBufferSize() para payloads JSON. O AsyncMqttClient adiciona publicação em QoS 1 e 2 com um design não bloqueante. Para firmware ESP32 de produção, o componente esp-mqtt da Espressif no ESP-IDF suporta MQTT 5, TLS e WebSocket e é mantido pelo próprio fabricante do chip. Comece pelo tutorial ESP32 MQTT para ter código Arduino funcionando, e pelo Paho MQTT C para dispositivos Linux.
Mobile: Swift, Kotlin, Flutter e React Native
Clientes mobile enfrentam uma restrição que servidores não têm: o sistema operacional suspende apps em segundo plano e encerra sockets ociosos. Seja qual for a biblioteca escolhida, planeje reconexões frequentes, use sessões persistentes ou retained messages para recuperar o atraso e use notificações push para tudo o que precisa chegar a um celular em repouso.
- iOS / macOS: o CocoaMQTT suporta MQTT 5, TLS e WebSocket. Veja MQTT no iOS com Swift.
- Android: Paho Java ou o cliente HiveMQ a partir de Kotlin, de preferência dentro de um componente ciente do ciclo de vida.
- Flutter: o
mqtt_clientcobre alvos de servidor e navegador a partir de uma única base de código Dart. Veja o tutorial de MQTT com Flutter. - React Native: MQTT.js sobre WebSocket é o caminho mais comum, com alguns polyfills. Veja MQTT com React Native.
Armadilhas que Parecem Bugs da Biblioteca
A maioria dos problemas atribuídos a uma biblioteca são, na verdade, problemas de configuração ou de projeto. Verifique estes primeiro:
| Sintoma | Causa real | Solução |
|---|---|---|
| Loop constante de conexão/desconexão | Dois processos compartilham um client ID | Gere IDs únicos; o broker derruba a sessão mais antiga |
| Nenhuma mensagem após reconectar | Clean session sem reassinatura | Reassine no callback de conexão, não apenas uma vez na inicialização |
| O event loop congela | Trabalho bloqueante dentro de um callback de mensagem | Repasse o trabalho para uma fila, um pool de threads ou uma task assíncrona |
| Payloads grandes descartados silenciosamente | Buffer do cliente ou limite de tamanho do broker | Aumente o buffer do cliente; respeite os limites do broker |
| Handshake TLS falha no dispositivo | CA raiz ausente ou relógio errado | Instale o pacote de CAs e sincronize a hora via NTP antes de conectar |
| Duplicatas em QoS 1 | Comportamento esperado de entrega "pelo menos uma vez" | Torne os handlers idempotentes; veja níveis de QoS MQTT explicados |
O tratamento de reconexão merece atenção especial em Python; o guia de reconexão do paho-mqtt explica as configurações de backoff. Para uma abordagem sistemática de verificação de um cliente antes de lançá-lo, leia testando clientes MQTT, e mantenha à mão os exemplos de mosquitto_pub e mosquitto_sub como um segundo cliente independente durante a depuração.
Migrando do Servidor MQTT Público para o Seu Próprio Broker
Todos os exemplos acima usam o servidor MQTT público anônimo, que é perfeito para comparar bibliotecas lado a lado: rode o subscriber Python, publique a partir de Go e veja a mensagem chegar. O servidor MQTT público, porém, é compartilhado, serve para testes e protótipos e pode ser lido por qualquer pessoa, então clientes de produção precisam de credenciais e de um broker isolado.
A ConnectMQ é um broker MQTT gerenciado que funciona com todas as bibliotecas deste guia, porque fala MQTT 3.1.1 e 5.0 padrão sobre TCP 1883, TLS 8883, WebSocket 8083 e WebSocket seguro 8084 (caminho /mqtt). Ao criar um broker no portal, você recebe um nome de usuário, uma senha e um client ID. Adaptar qualquer exemplo acima é uma mudança de três linhas, mostrada aqui para o paho-mqtt:
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()
A ConnectMQ vincula os client IDs às credenciais emitidas, então use o ID gerado exatamente como fornecido. Se você ainda está decidindo como hospedar seu broker, nosso guia sobre o cenário de broker MQTT na nuvem compara as opções serverless, dedicada e na sua própria nuvem.
Conecte Qualquer Biblioteca MQTT à ConnectMQ
Escolha a biblioteca que combina com a sua stack, rode o exemplo dela no broker.connectmq.com e, quando chegar a hora de ter topics privados, crie um broker gratuito em app.connectmq.com. O plano Serverless (Free) não exige cartão de crédito e oferece até 25 conexões, QoS até 1 e mensagens de 256 KB, o que é mais do que suficiente para construir e testar clientes em várias linguagens ao mesmo tempo.
Perguntas frequentes
Qual é a melhor biblioteca cliente MQTT?
Não existe uma única melhor; a escolha certa é a biblioteca mantida que combina com a sua linguagem e com o seu modelo de concorrência. paho-mqtt para Python, MQTT.js para JavaScript, MQTTnet para .NET e Paho ou rumqttc para Go e Rust são os padrões mais comuns e bem suportados.
Todas as bibliotecas cliente MQTT suportam MQTT 5?
Não. Várias bibliotecas populares, incluindo a PubSubClient para Arduino e o cliente Paho Go clássico, implementam apenas MQTT 3.1.1. Se você precisa de assinaturas compartilhadas, expiração de mensagens ou reason codes, confirme o suporte a MQTT 5 antes de adotar uma biblioteca.
Clientes escritos em linguagens diferentes conseguem conversar entre si?
Sim. O broker roteia bytes, não objetos de linguagem, então um publisher em Python e um subscriber em C# se comunicam normalmente, desde que concordem sobre os topics e o formato do payload. JSON é o formato comum mais fácil para começar.
Qual biblioteca devo usar no navegador?
MQTT.js sobre WebSocket seguro é a escolha padrão. Conecte-se a wss://broker.connectmq.com:8084/mqtt, porque navegadores não conseguem abrir sockets TCP puros e páginas HTTPS bloqueiam conexões WebSocket inseguras.
Por que meu cliente funciona no servidor MQTT público, mas não em um broker privado?
Geralmente faltam credenciais, o client ID não corresponde ao emitido ou o TLS não está ativado. Verifique o reason code do CONNACK informado pela sua biblioteca; ele indica exatamente qual desses itens está errado.



