¿Cómo funciona MQTT? En pocas palabras, los clientes abren una única conexión de larga duración con un broker, declaran qué topics les interesan y el broker reenvía cada mensaje publicado a los suscriptores que coinciden. En este artículo seguirás ese proceso paquete a paquete, desde la conexión TCP pasando por CONNECT, SUBSCRIBE, PUBLISH, keep alive y la desconexión, y reproducirás tú mismo toda la traza en un servidor MQTT público gratuito.
Los tres roles: publicador, suscriptor y broker
MQTT solo tiene dos tipos de participantes: clientes y brokers. Un cliente puede publicar, suscribirse o ambas cosas. El broker se sitúa en medio, recibe cada mensaje y decide quién lo recibe.
- Los publicadores envían mensajes a un topic, una cadena como
plant1/line2/temperature. No saben ni les importa quién los recibe. - Los suscriptores indican al broker qué topics, o patrones de topics, quieren. No saben quién envía.
- El broker autentica a los clientes, lleva el registro de suscripciones y sesiones y enruta cada mensaje a todos los suscriptores que coinciden.
Este desacoplamiento es el corazón del diseño. Un sensor no necesita la dirección IP de un panel, los dos no necesitan estar conectados al mismo tiempo si las sesiones son persistentes, y añadir un quinto consumidor no exige ningún cambio en el sensor. Para saber más sobre el trabajo del broker, consulta qué hace un broker MQTT, y para el patrón en sí, el modelo de publicación/suscripción de MQTT.
Paso 1: abrir una conexión de red
MQTT funciona sobre un flujo de bytes fiable y ordenado, normalmente TCP. El cliente abre una conexión TCP con el broker, en el puerto 1883 para MQTT sin cifrar o en el 8883 para MQTT sobre TLS. Los navegadores, que no pueden abrir sockets TCP crudos, transportan MQTT dentro de un WebSocket (en ConnectMQ, en el 8083 o el 8084 con la ruta /mqtt). Todavía no ha ocurrido nada específico de MQTT; esto es solo la tubería.
Con TLS, se produce entonces un handshake: el cliente comprueba el certificado del broker y ambos lados acuerdan las claves de cifrado. A partir de ahí, todos los paquetes MQTT van cifrados.
Paso 2: CONNECT y CONNACK
El primer paquete del cliente debe ser CONNECT. Contiene:
| Campo | Propósito |
|---|---|
| Nombre y nivel del protocolo | MQTT y 4 (3.1.1) o 5 (5.0) |
| Client ID | Identifica la sesión; debe ser único por conexión |
| Clean session / clean start | Empezar de cero o reanudar una sesión almacenada |
| Keep alive | Máximo de segundos entre paquetes del cliente |
| Usuario y contraseña | Credenciales opcionales |
| Last Will | Mensaje opcional que el broker publica si el cliente desaparece |
| Propiedades (MQTT 5) | Caducidad de sesión, receive maximum, tamaño máximo de paquete y más |
El broker valida todo esto y responde con CONNACK. En MQTT 5 incluye un código de motivo: 0x00 si todo fue bien, o un error como credenciales incorrectas, no autorizado o, en un broker con cuotas, 0x97 quota exceeded. También indica si se reanudó una sesión anterior (flag session present) y puede informar al cliente de los límites del servidor. Hasta que llega un CONNACK correcto, el cliente no debe enviar nada más.
Paso 3: SUBSCRIBE y SUBACK
Un cliente que quiere recibir mensajes envía SUBSCRIBE con uno o varios filtros de topic y un QoS solicitado para cada uno. Los filtros pueden incluir comodines: + coincide exactamente con un nivel y # coincide con todo lo que hay por debajo de un nivel. Por ejemplo, plant1/+/temperature coincide con plant1/line2/temperature, pero no con plant1/line2/motor/temperature.
El broker responde con SUBACK, indicando el QoS concedido (o un código de error) para cada filtro. El QoS concedido puede ser inferior al solicitado si el broker lo limita. Si existen retained messages en los topics que coinciden, el broker los envía de inmediato; así es como un panel nuevo conoce al instante el estado actual.
Paso 4: PUBLISH y los handshakes de QoS
Para enviar datos, un cliente envía PUBLISH con un nombre de topic, un payload (cualquier secuencia de bytes, a menudo JSON), un nivel de QoS y un flag retain. Lo que ocurre después depende del QoS:
- QoS 0, como máximo una vez. PUBLISH y listo. Sin confirmación; si la conexión se cae en mal momento, el mensaje se pierde.
- QoS 1, al menos una vez. El receptor responde con PUBACK. Si el emisor no lo recibe, reenvía con el flag de duplicado activado, así que el receptor puede ver el mensaje dos veces.
- QoS 2, exactamente una vez. Un intercambio en cuatro pasos: PUBLISH, PUBREC, PUBREL, PUBCOMP. Más lento, pero sin duplicados.
Estos handshakes ocurren salto a salto: una vez entre el publicador y el broker y, por separado, entre el broker y cada suscriptor. Después, el broker reenvía el mensaje a cada cliente cuyo filtro coincide, usando el menor entre el QoS de publicación y el QoS concedido a la suscripción. Los compromisos completos están en los niveles de QoS de MQTT explicados.
Con el flag retain activado, el broker además guarda el mensaje como último valor conocido de ese topic y se lo entrega a los futuros suscriptores.
Paso 5: keep alive con PINGREQ y PINGRESP
Aunque esté inactivo, un cliente debe seguir demostrando que está vivo dentro del intervalo de keep alive. Si no tiene nada que publicar, envía PINGREQ y el broker responde con PINGRESP. Si el broker no recibe nada durante aproximadamente una vez y media el periodo de keep alive, considera muerto al cliente, cierra la conexión y publica su Last Will, si se configuró uno. Así es como los paneles saben que un dispositivo se ha desconectado sin que nadie tenga que sondear.
Paso 6: DISCONNECT y sesiones
Un cierre limpio envía DISCONNECT, que indica al broker que no publique el Last Will. Lo que sobrevive depende de los ajustes de sesión: con clean start y sin caducidad de sesión, el broker olvida las suscripciones del cliente. Con una sesión persistente (caducidad de sesión de MQTT 5 mayor que cero), el broker conserva las suscripciones y pone en cola los mensajes QoS 1 y 2 hasta que el cliente vuelve o vence la caducidad.
Reproduce tú mismo la traza
Puedes observar todo el ciclo de vida en el servidor MQTT público gratuito en broker.connectmq.com, pensado para pruebas y no para datos de producción. Los clientes de Mosquitto imprimen cada paquete con -d. Elige primero un ID aleatorio único; aquí es q7m3x9.
# Terminal 1: suscriptor con salida de depuración
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-q7m3x9 -V mqttv5 -d \
-t 'connectmq/demo/q7m3x9/#' -q 1
# Terminal 2: publicador con salida de depuración
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-q7m3x9 -V mqttv5 -d \
-t 'connectmq/demo/q7m3x9/sensor/temp' -m '{"c":21.7}' -q 1
La salida del suscriptor tiene este aspecto (los detalles varían según la versión):
Client sub-q7m3x9 sending CONNECT
Client sub-q7m3x9 received CONNACK (0)
Client sub-q7m3x9 sending SUBSCRIBE (Mid: 1, Topic: connectmq/demo/q7m3x9/#, QoS: 1, Options: 0x00)
Client sub-q7m3x9 received SUBACK
Subscribed (mid: 1): 1
Client sub-q7m3x9 received PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client sub-q7m3x9 sending PUBACK (m1, rc0)
{"c":21.7}
Client sub-q7m3x9 sending PINGREQ
Client sub-q7m3x9 received PINGRESP
Y la del publicador:
Client pub-q7m3x9 sending CONNECT
Client pub-q7m3x9 received CONNACK (0)
Client pub-q7m3x9 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client pub-q7m3x9 received PUBACK (Mid: 1, RC:0)
Client pub-q7m3x9 sending DISCONNECT
Lee los flags de la línea PUBLISH: d0 (no es un duplicado), q1 (QoS 1), r0 (no retenido), m1 (identificador de paquete 1). Prueba con -q 2 y verás PUBREC, PUBREL y PUBCOMP; añade -r al publicador, reinicia el suscriptor y el mensaje retenido llegará justo después de SUBACK. El área pública puede leerla cualquiera, así que envía solo datos de prueba.
El mismo flujo en Python
Las bibliotecas ocultan los paquetes tras callbacks, pero cada uno se corresponde con un paso de los anteriores.
import time
import uuid
import paho.mqtt.client as mqtt
PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"
def on_connect(client, userdata, flags, reason_code, properties): # CONNACK
print("CONNACK:", reason_code)
client.subscribe(f"{PREFIX}/#", qos=1) # SUBSCRIBE
def on_subscribe(client, userdata, mid, reason_codes, properties): # SUBACK
print("SUBACK:", [str(rc) for rc in reason_codes])
client.publish(f"{PREFIX}/sensor/temp", '{"c":21.7}', qos=1) # PUBLISH
def on_publish(client, userdata, mid, reason_code, properties): # PUBACK
print("PUBACK for mid", mid)
def on_message(client, userdata, msg): # PUBLISH entrante
print("Message:", msg.topic, msg.payload.decode())
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"trace-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_publish = on_publish
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=30) # TCP + CONNECT
client.loop_start()
time.sleep(5)
client.disconnect() # DISCONNECT
client.loop_stop()
Malentendidos habituales
- "El broker guarda todos los mensajes." Solo los retained messages (uno por topic) y los mensajes en cola de las sesiones persistentes. MQTT no es una base de datos ni un log.
- "Los topics hay que crearlos antes." No, los topics existen en el momento en que alguien publica o se suscribe.
- "QoS 2 de extremo a extremo." El QoS se aplica por salto y se rebaja al nivel de la suscripción.
- "Los client IDs se pueden compartir." Una segunda conexión con el mismo ID expulsa a la primera.
- "MQTT usa UDP." El MQTT estándar necesita TCP u otro flujo fiable; MQTT-SN es la variante para UDP y redes similares.
Para profundizar, el tutorial de MQTT construye un proyecto completo, los paquetes de control de MQTT detalla cada tipo de paquete y las especificaciones oficiales están publicadas en mqtt.org.
Prueba MQTT en ConnectMQ
Experimenta libremente en broker.connectmq.com y, cuando quieras topics privados y autenticados, crea un broker Serverless gratuito en app.connectmq.com sin tarjeta de crédito. ConnectMQ es un broker MQTT en la nube compatible con MQTT 3.1.1 y 5.0, con un cliente en el navegador y un explorador de topics en vivo, para que puedas observar en tiempo real los flujos descritos aquí. Cuando pases a producción, funciona como un broker MQTT gestionado.
Preguntas frecuentes
¿Cómo funciona MQTT en pocas palabras?
Los dispositivos se conectan a un broker central, se suscriben a los topics que les interesan y publican mensajes en topics. El broker reenvía cada mensaje a todos los suscriptores que coinciden.
¿Los publicadores y los suscriptores se conectan directamente entre sí?
No. Cada cliente se conecta solo al broker, y por eso los dispositivos nunca necesitan las direcciones de los demás.
¿Qué ocurre si un suscriptor está desconectado cuando se publica un mensaje?
Con una sesión persistente y QoS 1 o 2, el broker pone el mensaje en cola hasta que el suscriptor se reconecta o la sesión caduca. Si no, el mensaje no se entrega a ese cliente, aunque un mensaje retenido le seguirá dando el último valor.
¿Qué puerto usa MQTT?
El 1883 para TCP sin cifrar y el 8883 para TLS. Los puertos WebSocket varían según el broker; ConnectMQ usa el 8083 y el 8084 con la ruta /mqtt.



