El tamaño máximo de un mensaje MQTT según el protocolo es de 268.435.455 bytes, unos 256 MB. En la práctica nunca llegarás tan lejos: los brokers, los servicios cloud y las librerías cliente fijan límites más bajos, y algunos descartan los mensajes demasiado grandes sin avisarte. Esta guía explica dónde vive cada límite, cómo MQTT 5 lo hace visible y cómo probar el techo real de tu broker antes de que lo descubra una imagen de firmware o una captura de cámara.
De dónde sale el límite de 256 MB
Todo paquete de control MQTT empieza con una cabecera fija que contiene el Remaining Length: el número de bytes que vienen a continuación. Se codifica como un entero de longitud variable de como máximo cuatro bytes, con siete bits útiles cada uno, así que el valor más alto es 2^28 − 1 = 268.435.455.
Ese número cubre todo el resto del paquete, no solo tus datos. Un PUBLISH contiene además:
- el nombre del topic (longitud de 2 bytes + bytes UTF-8),
- un packet identifier de 2 bytes para QoS 1 y 2,
- en MQTT 5, un bloque de propiedades (content type, user properties, message expiry…).
Por tanto, el payload más grande posible es algo menor de 256 MB, y se reduce con topics largos y muchas user properties. La calculadora de tamaño de paquetes MQTT muestra la sobrecarga exacta para un topic, QoS y payload concretos.
Los límites con los que de verdad te encuentras
| Capa | Dónde se define el límite | Comportamiento típico al superarlo |
|---|---|---|
| Protocolo | Remaining Length (4 bytes) | El paquete ni siquiera se puede codificar |
| Mosquitto | max_packet_size, antes message_size_limit | MQTT 5: desconexión con 0x95; 3.1.1: mensaje descartado o conexión cerrada |
| EMQX | mqtt.max_packet_size (por defecto 1 MB) | Conexión cerrada, error en el log del broker |
| HiveMQ | max-packet-size en la configuración MQTT | Los clientes MQTT 5 reciben 0x95; los 3.1.1 se desconectan |
| Servicios IoT cloud | Cuotas del servicio | AWS IoT Core limita los payloads a 128 KB, Azure IoT Hub los mensajes device-to-cloud a 256 KB; consulta las páginas de cuotas actuales |
| Librería cliente | Buffers internos, Maximum Packet Size de MQTT 5 | Error al publicar o descarte silencioso al recibir |
| Ruta de red | Proxies, balanceadores, gateways WebSocket | Timeouts o resets en enlaces lentos |
Los valores por defecto cambian entre versiones, así que usa esta tabla como un mapa de dónde mirar, no como una lista de números garantizados. Lee la referencia de configuración de la versión exacta que ejecutas.
Configuración de Mosquitto
Mosquitto 2.x tiene dos opciones relacionadas:
# Maximum size of any MQTT packet the broker accepts, in bytes.
# MQTT 5 clients are told this value in CONNACK.
max_packet_size 1048576
# Older option: maximum PUBLISH payload size. Deprecated in favour of
# max_packet_size, but still found in many existing configs.
# message_size_limit 1048576Si no defines ninguna, Mosquitto no impone un límite inferior al del protocolo, lo que significa que un solo cliente puede hacer que el broker reserve cientos de megabytes. Fijar un límite explícito forma parte de una configuración de producción sensata; el generador de mosquitto.conf lo incluye.
Maximum Packet Size en MQTT 5
MQTT 3.1.1 no permite negociar el tamaño. MQTT 5 añade la propiedad Maximum Packet Size en ambas direcciones:
- CONNECT → broker: el cliente anuncia el paquete más grande que está dispuesto a recibir. El broker no debe enviar nada mayor; si un mensaje que coincide es demasiado grande para ese suscriptor, el broker lo descarta solo para ese cliente.
- CONNACK → cliente: el broker anuncia el paquete más grande que acepta. Una librería cliente bien hecha se niega a enviar paquetes mayores. Si aun así se envía uno, el broker desconecta con el reason code 0x95 Packet too large.
Ese segundo caso es el error que la gente busca. Su significado y los códigos relacionados están en la referencia de reason codes MQTT y se explican en detalle en MQTT packet too large.
Prueba rápida con mosquitto_pub
Genera archivos de tamaños conocidos y envíalos a través del broker. -f envía un archivo como payload; -N evita que mosquitto_sub añada un salto de línea, así el número de bytes es exacto.
HOST=broker.connectmq.com
TOPIC="testmqtt/payload-$RANDOM/blob"
for size in 64K 512K 1M 4M; do
head -c "$size" /dev/urandom > "/tmp/blob-$size"
done
# Terminal 1: recibir un mensaje y contar sus bytes
mosquitto_sub -h "$HOST" -t "$TOPIC" -V mqttv5 -C 1 -W 30 -N | wc -c
# Terminal 2: enviar un tamaño cada vez
mosquitto_pub -h "$HOST" -t "$TOPIC" -V mqttv5 -q 1 -f /tmp/blob-1M -d-d muestra cada paquete enviado y recibido, así que puedes ver si el PUBLISH salió del cliente y si la conexión se cerró justo después. Si wc -c imprime el tamaño del archivo, el mensaje llegó; si mosquitto_sub agota el tiempo tras 30 segundos, no llegó. Para simular un suscriptor limitado, añade -D connect maximum-packet-size 65536 a mosquitto_sub y verás cómo los mensajes grandes desaparecen solo para ese cliente.
Barrido de tamaños automatizado en Python
Para obtener una respuesta repetible, este script con paho-mqtt 2.x publica payloads de tamaño creciente con QoS 1, verifica cada uno con un hash SHA-256 y se detiene en el primer fallo. También muestra el límite que anuncia el broker.
import hashlib, os, threading, time, uuid
import paho.mqtt.client as mqtt
HOST, PORT = "broker.connectmq.com", 1883
TOPIC = f"testmqtt/payload-{uuid.uuid4().hex[:8]}/blob"
SIZES = [1_024, 65_536, 262_144, 1_048_576, 4_194_304, 16_777_216]
TIMEOUT = 30
result, got = {}, threading.Event()
def on_connect(client, userdata, flags, reason_code, properties):
limit = getattr(properties, "MaximumPacketSize", None)
print(f"connected: {reason_code}, broker max packet = {limit or 'not advertised'}")
def on_disconnect(client, userdata, flags, reason_code, properties):
print(f"disconnected: {reason_code}")
def on_message(client, userdata, msg):
result["digest"] = hashlib.sha256(msg.payload).hexdigest()
got.set()
def make_client(name):
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"{name}-{uuid.uuid4().hex[:6]}", protocol=mqtt.MQTTv5)
# c.username_pw_set(os.environ["MQTT_USER"], os.environ["MQTT_PASS"])
c.on_connect, c.on_disconnect, c.on_message = on_connect, on_disconnect, on_message
c.connect(HOST, PORT)
c.loop_start()
return c
sub = make_client("sweep-sub")
sub.subscribe(TOPIC, qos=1)
pub = make_client("sweep-pub")
time.sleep(2)
for size in SIZES:
payload = os.urandom(size)
got.clear()
start = time.perf_counter()
info = pub.publish(TOPIC, payload, qos=1)
if info.rc != mqtt.MQTT_ERR_SUCCESS:
print(f"{size:>10} B FAIL publish rc={info.rc}")
break
if not got.wait(TIMEOUT):
print(f"{size:>10} B FAIL not delivered within {TIMEOUT}s")
break
ok = result["digest"] == hashlib.sha256(payload).hexdigest()
print(f"{size:>10} B {'OK ' if ok else 'BAD '} {(time.perf_counter() - start) * 1000:.0f} ms")
pub.loop_stop(); sub.loop_stop()Salidas típicas y su significado:
- Todos los tamaños OK: el broker acepta al menos 16 MB. Decide si eso es realmente lo que quieres.
- Entregado hasta N y luego "not delivered", sin desconexión: el broker descarta en silencio los mensajes demasiado grandes, o se aplicó el límite del propio suscriptor.
- "disconnected: Packet too large": un broker MQTT 5 aplicando
max_packet_size. El último tamaño que pasó es tu techo práctico. - La latencia crece mucho con el tamaño: estás midiendo ancho de banda, no el broker. Compara las cifras con la velocidad de subida de tu conexión.
Ejecuta el barrido una vez por TCP y otra por WebSockets (puerto 8083 u 8084 con la ruta /mqtt): los proxies delante de los listeners WebSocket a veces tienen sus propios límites de frame o de buffer. También puedes probar payloads individuales de forma interactiva en el cliente MQTT online.
Los payloads grandes tienen efectos secundarios
Aunque el broker acepte un mensaje de 10 MB, no sale gratis:
- Bloqueo de cabeza de línea. MQTT funciona sobre una única conexión TCP. Mientras se transmite un PUBLISH grande, nada más avanza por esa conexión, incluidos comandos pequeños y urgentes y los paquetes PINGREQ. En un enlace móvil lento esto puede provocar timeouts de keep-alive.
- Memoria. El broker suele mantener el mensaje completo en memoria, una vez por cada suscriptor en cola con sesión persistente desconectada. Los mensajes retenidos grandes se quedan ahí indefinidamente.
- Reintentos. Con QoS 1 o 2, una conexión caída implica reenviar el paquete entero: no hay reanudación.
- Fan-out. Un mensaje de 5 MB para 200 suscriptores son 1 GB de tráfico de salida. Consulta la sobrecarga de ancho de banda de MQTT para hacer las cuentas.
Patrones de diseño para datos grandes
- Mantén los mensajes pequeños por defecto. Telemetría, eventos y comandos deberían medirse en bytes o kilobytes. Codificaciones binarias como CBOR o Protobuf reducen considerablemente los payloads JSON.
- Divide los archivos grandes. Pártelos en fragmentos numerados (por ejemplo de 64 KB) en
…/file/<id>/<n>, envía un manifiesto con el tamaño total y el hash, y reensambla en el receptor. Transferencia de archivos por MQTT recorre una implementación completa. - Envía un puntero, no el archivo. Sube el archivo a un almacenamiento de objetos por HTTP y publica la URL y los metadatos por MQTT. Es la opción habitual para imágenes de cámara y firmware.
- Fija un límite explícito en el broker algo por encima de tu mensaje legítimo más grande, para que un cliente defectuoso no pueda agotar la memoria.
Publica un payload de prueba en tu navegador
El techo de 256 MB del protocolo es una cifra teórica; el límite que importa es el más pequeño de toda tu ruta, desde el buffer del cliente hasta la configuración del broker y la cuota del cloud. Mídelo con un barrido de tamaños, hazlo explícito en la configuración del broker y diseña cualquier cosa mayor como fragmentos o punteros en lugar de un único mensaje.
Preguntas frecuentes
¿Cuál es el tamaño máximo de un mensaje MQTT?
El protocolo permite paquetes de control de hasta 268.435.455 bytes (unos 256 MB), porque el campo Remaining Length ocupa como máximo cuatro bytes. El payload útil es algo menor, y casi todos los brokers y servicios cloud imponen un límite mucho más bajo.
¿Por qué mi mensaje MQTT grande desaparece sin ningún error?
En MQTT 3.1.1 el broker no puede rechazar un PUBLISH concreto indicando un motivo, así que muchos brokers descartan en silencio los mensajes demasiado grandes o cierran la conexión. Usa MQTT 5, lee el Maximum Packet Size del CONNACK y vigila el reason code 0x95 Packet too large.
¿Debería enviar archivos o imágenes por MQTT?
Los archivos pequeños de unos cientos de kilobytes funcionan bien en la mayoría de brokers. Para archivos mayores, divídelos en fragmentos numerados o publica una URL a un almacenamiento de objetos, para que un mensaje enorme no bloquee la conexión ni agote la memoria del broker.

