El QoS máximo en MQTT es la parte de la calidad de servicio que más sorprende: puedes publicar con QoS 2 y aun así recibir un mensaje con QoS 0. El nivel que se usa realmente en una entrega depende del publicador, del suscriptor y de los límites propios del broker. En este artículo aprenderás cómo se calcula el QoS efectivo, cómo los brokers anuncian e imponen un máximo y cómo comprobar exactamente qué obtiene tu conexión.
El QoS se negocia en cada salto
MQTT tiene tres niveles de QoS: 0 (como máximo una vez), 1 (al menos una vez) y 2 (exactamente una vez). Si son nuevos para ti, empieza por niveles de QoS de MQTT explicados.
La clave es que el QoS no es de extremo a extremo. Un mensaje recorre dos saltos independientes:
- Del publicador al broker, con el QoS que el publicador eligió para ese PUBLISH.
- Del broker a cada suscriptor, con un QoS que el broker calcula para esa suscripción.
Cada salto tiene su propio intercambio. El PUBACK del publicador procede del broker, no del suscriptor, de modo que un publicador nunca sabe si algún suscriptor ha recibido el mensaje.
Cómo se calcula el QoS efectivo
Para cada suscriptor, el broker entrega con el menor de dos valores: el QoS del PUBLISH entrante y el QoS concedido a la suscripción coincidente.
| QoS de publicación | QoS de suscripción | QoS entregado |
|---|---|---|
| 0 | 2 | 0 |
| 1 | 0 | 0 |
| 1 | 2 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 2 |
En la práctica importan dos consecuencias:
- Suscribirse con QoS 2 no mejora nada. Si un sensor publica con QoS 0, todos los suscriptores reciben QoS 0, independientemente de lo que hayan pedido.
- Un suscriptor puede rebajarlo a propósito. Un panel al que solo le interesa el último valor puede suscribirse con QoS 0 a la telemetría publicada con QoS 1 y ahorrarse los acuses de recibo en su propio enlace.
Si un filtro de suscripción se solapa con otro (por ejemplo plant/# y plant/line1/+), el broker puede entregar el mensaje una vez con el QoS coincidente más alto o, en MQTT 5, una vez por suscripción, según la implementación. Evita en lo posible las suscripciones solapadas con distinto QoS.
Cómo limitan el QoS los brokers
Un broker no está obligado a admitir todos los niveles para todos los clientes. Dispone de dos mecanismos para indicarlo.
QoS concedido en SUBACK. Cuando un cliente se suscribe, el broker responde con un SUBACK que contiene el QoS concedido para cada filtro. Puede conceder un nivel inferior al solicitado. En MQTT 3.1.1 los códigos de retorno son 0, 1, 2 o 0x80 en caso de fallo; en MQTT 5 son reason codes, donde 0x00, 0x01 y 0x02 significan QoS concedido 0, 1 y 2. Un cliente bien escrito comprueba este valor en lugar de suponer que se ha respetado su petición.
Maximum QoS en CONNACK (MQTT 5). Un broker MQTT 5 que no admite QoS 2, o QoS 1 y 2, incluye una propiedad Maximum QoS en el CONNACK. Si la propiedad no aparece, QoS 2 está admitido. Un cliente que publique por encima del máximo anunciado incumple el protocolo, y el broker lo desconecta con el reason code 0x9B (QoS no soportado). En MQTT 3.1.1 no existe esta propiedad, así que los clientes lo descubren por las malas.
Los brokers limitan el QoS por buenas razones: QoS 2 exige guardar más estado y cuatro paquetes por mensaje en cada salto, lo que se acumula en una infraestructura compartida y multiinquilino.
Probar el QoS máximo de MQTT en el servidor público
El servidor MQTT público gratuito en broker.connectmq.com, pensado para pruebas y no para datos de producción, admite QoS de 0 a 2, así que es un buen lugar para ver las rebajas causadas por la combinación de publicación y suscripción. El flag -d hace que las herramientas de Mosquitto impriman los paquetes del protocolo, incluido el QoS concedido en el SUBACK.
Terminal 1, suscripción solicitando QoS 1:
mosquitto_sub -d -h broker.connectmq.com -p 1883 -i mq-sub-u3x7 -q 1 \
-t 'connectmq/demo/u3x7/#' -F 'qos=%q %t %p'
En la salida de depuración busca una línea como Client mq-sub-u3x7 received SUBACK seguida de Subscribed (mid: 1): 1. El último número es el QoS concedido.
Terminal 2, publicación en cada nivel:
for q in 0 1 2; do
mosquitto_pub -h broker.connectmq.com -p 1883 -i mq-pub-u3x7 -q $q \
-t connectmq/demo/u3x7/test -m "published at qos $q"
done
La terminal 1 imprime qos=0, qos=1 y qos=1. La publicación con QoS 2 se rebajó a 1 en el camino hacia este suscriptor porque eso es lo que pidió la suscripción. Reinicia el suscriptor con -q 2 y la tercera línea pasa a ser qos=2.
Comprobar el QoS concedido y el máximo desde código
Este script con paho-mqtt 2.x se conecta con MQTT 5, imprime el Maximum QoS anunciado por el broker si existe, se suscribe con QoS 2 e imprime lo que se le ha concedido:
import uuid
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
TOPIC = "connectmq/demo/u3x7/check"
def on_connect(client, userdata, flags, reason_code, properties):
max_qos = getattr(properties, "MaximumQoS", None)
if max_qos is None:
print("CONNACK: no Maximum QoS property, QoS 2 supported")
else:
print(f"CONNACK: broker maximum QoS is {max_qos}")
client.subscribe(TOPIC, qos=2)
def on_subscribe(client, userdata, mid, reason_code_list, properties):
rc = reason_code_list[0]
if rc.is_failure:
print("subscription refused:", rc)
else:
print(f"SUBACK: requested 2, granted {rc.value}")
client.disconnect()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"qoscheck-{uuid.uuid4().hex[:8]}",
protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.connect(BROKER, 1883, keepalive=30)
client.loop_forever()
Ejecuta el mismo script contra tu broker de producción con tus credenciales reales antes de confiar en un nivel de QoS. Tarda unos segundos y elimina las conjeturas.
QoS de los mensajes retenidos y del will
La misma regla del mínimo se aplica a los mensajes que el broker envía por iniciativa propia. Un mensaje retenido se almacena con el QoS con el que se publicó, y un nuevo suscriptor lo recibe con el menor entre ese QoS y el QoS concedido a su suscripción. Un Last Will se publica con el QoS del will fijado en el CONNECT, y cada suscriptor lo recibe, de nuevo, con el menor de los dos. Si el QoS máximo del broker es inferior al QoS del will que solicitas, un broker MQTT 5 puede rechazar la conexión con el reason code 0x9B, así que mantén el QoS del will dentro del límite anunciado.
Lista de comprobación práctica
- Decide el QoS de cada topic según lo que cueste un mensaje perdido o duplicado.
- Publica con ese QoS; los suscriptores no pueden subirlo.
- Comprueba el QoS concedido en el SUBACK y regístralo cuando sea inferior al solicitado.
- Con MQTT 5, lee el Maximum QoS del CONNACK y ajusta tus publicaciones a él.
- Diseña los consumidores para el QoS que realmente obtienes: idempotentes con QoS 1 (consulta mensajes duplicados MQTT) y tolerantes a huecos con QoS 0.
- Evita suscripciones solapadas con distinto QoS en un mismo cliente.
Resolución de problemas de QoS
El cliente se desconecta justo después de publicar. Si el reason code es 0x9B, has publicado por encima del máximo del broker. Baja el QoS o pásate a un plan o a un broker que lo admita. La lista completa de códigos está en reason codes de MQTT.
El suscriptor recibe QoS 0 aunque se suscribió con QoS 1. El publicador está usando QoS 0. Corrígelo en el origen.
La librería informa de éxito pero se pierden mensajes. Algunas librerías ignoran el QoS concedido. Comprueba tú mismo el SUBACK como en el script anterior.
QoS 2 es lento. Cada mensaje necesita cuatro paquetes por salto. Para telemetría de alta frecuencia, QoS 1 con deduplicación suele ofrecer mejor rendimiento.
Las reglas normativas están en la especificación OASIS MQTT 5.0, en las secciones sobre las propiedades de SUBACK y CONNACK.
Límites de QoS en los planes de ConnectMQ
ConnectMQ es explícito sobre el QoS de cada plan. El plan Serverless gratuito admite QoS hasta 1, el plan Serverless de pago añade QoS 2 junto con mensajes más grandes y suscripciones compartidas, y las opciones Dedicated, BYOC y Self Managed Enterprise te dan un clúster aislado. El servidor público permite QoS de 0 a 2 para experimentar. Ejecuta el script de comprobación con tus credenciales de ConnectMQ para confirmar lo que informa tu conexión. Si estás comparando proveedores, nuestra visión general de un broker MQTT gestionado y el tutorial de MQTT son buenas lecturas para continuar.
Empieza con ConnectMQ
Crea un broker gratis en app.connectmq.com con el plan Serverless, sin tarjeta de crédito. Empieza con QoS 0 y 1 y pasa al plan de pago para tener QoS 2 cuando la carga de tu broker MQTT en la nube necesite entrega exactamente una vez.
Preguntas frecuentes
¿Qué es el QoS efectivo en MQTT?
Es el QoS que se usa para entregar un mensaje a un suscriptor: el menor entre el QoS de publicación y el QoS concedido a la suscripción.
¿Puede un suscriptor obtener un QoS más alto que el que usó el publicador?
No. Un mensaje publicado con QoS 0 se entrega siempre con QoS 0, independientemente de la suscripción.
¿Cómo sé cuál es el QoS máximo del broker?
En MQTT 5, lee la propiedad Maximum QoS del CONNACK; si no aparece, QoS 2 está admitido. En MQTT 3.1.1, comprueba el QoS concedido en el SUBACK.
¿Qué ocurre si publico por encima del QoS máximo?
Un broker MQTT 5 desconecta al cliente con el reason code 0x9B, QoS no soportado.



