El intervalo keep alive de MQTT es el número de segundos durante los cuales un cliente promete no quedarse nunca en silencio, y es la principal herramienta que tiene un broker para detectar conexiones muertas. En esta guía aprenderás con exactitud cómo funcionan PINGREQ, PINGRESP y la regla del timeout de 1,5x, cómo interactúa el keep alive con los routers NAT, los enlaces móviles y la duración de la batería, y con qué valores conviene empezar en tus dispositivos.
Qué hace realmente el intervalo keep alive de MQTT
Cuando un cliente envía CONNECT, incluye un campo Keep Alive de dos bytes expresado en segundos. Ese valor es un contrato: "te enviaré algún paquete de control al menos una vez en este periodo". Cualquier paquete cuenta, ya sea un PUBLISH, un SUBSCRIBE o un PUBACK. Solo cuando el cliente no tiene nada más que enviar recurre a un diminuto paquete PINGREQ, y el broker responde con PINGRESP.
El keep alive existe porque TCP, por sí solo, detecta mal a los pares caídos. Si un dispositivo se queda sin alimentación o su módem móvil se desconecta de la red, nunca se envía un paquete FIN o RST. Desde el punto de vista del broker, el socket sigue "abierto" para siempre, y cualquier suscriptor que espere el Last Will and Testament del dispositivo también espera para siempre. El keep alive da a ambas partes un plazo límite.
La regla del timeout de 1,5x
La especificación de MQTT establece que, si el broker no recibe nada de un cliente en una vez y media el intervalo keep alive, debe cerrar la conexión de red como si hubiera fallado. Eso significa:
| Keep alive | El broker se rinde tras | Uso típico |
|---|---|---|
| 15 s | 22,5 s | Dashboards interactivos, failover rápido |
| 30 s | 45 s | Dispositivos conectados a la red eléctrica con Wi-Fi poco fiable |
| 60 s | 90 s | Valor por defecto sensato para la mayoría de dispositivos |
| 120 s | 180 s | Dispositivos móviles que vigilan el consumo de datos |
| 300 s | 450 s | Gateways poco habladores en enlaces estables |
| 0 | Nunca | Keep alive desactivado (evítalo en producción) |
El cliente tiene su propia parte del trato. Si envía PINGREQ y no recibe PINGRESP en un "tiempo razonable" (la mayoría de las librerías usan el valor de keep alive o un timeout fijo), debe considerar la conexión rota y reconectarse. Así descubre el cliente un socket semiabierto en su lado.
Qué ocurre cuando salta el timeout
Cuando el broker cierra una conexión por keep alive, la trata como una desconexión anómala. Consecuencias prácticas:
- Se publica el mensaje de will del cliente (tras el will delay, si lo has configurado en MQTT 5; consulta el will delay interval de MQTT).
- Si el cliente tenía una sesión persistente, el broker conserva sus suscripciones y empieza a encolar para él los mensajes QoS 1 y QoS 2.
- Los topics de estado online y los dashboards pasan a "offline".
Por tanto, el keep alive controla directamente la rapidez con la que tu sistema se entera de que algo ha ido mal.
Cómo elegir un valor de keep alive en MQTT
No existe un número correcto universal. Estás equilibrando velocidad de detección frente a tráfico y consumo energético.
Velocidad de detección
Un intervalo más corto significa que el broker y los suscriptores se enteran antes de los fallos. Si un dashboard de operador debe mostrar una máquina como offline en medio minuto, un keep alive de 60 segundos (detección en 90 segundos) no cumplirá ese requisito, mientras que 15 o 20 segundos sí.
Timeouts de inactividad de NAT y firewalls
Esta es la trampa en la que caen la mayoría de los equipos. Los routers domésticos, los firewalls corporativos, los balanceadores de carga en la nube y, sobre todo, los gateways NAT de los operadores móviles eliminan los mapeos TCP que llevan un tiempo inactivos. Una vez desaparecido el mapeo, el siguiente paquete del cliente no llega a ninguna parte y el broker solo lo nota al cumplirse el plazo de 1,5x. Si tu keep alive es más largo que el timeout de inactividad NAT más corto del trayecto, sufrirás desconexiones misteriosas cada pocos minutos. Los timeouts NAT de los operadores varían mucho y no siempre están documentados, así que en enlaces móviles es más seguro mantenerse bastante por debajo de unos pocos minutos.
Batería y consumo de datos
Cada ida y vuelta PINGREQ/PINGRESP supone solo 2 bytes de payload MQTT en cada sentido, más la sobrecarga de TCP/IP (y del registro TLS). En Wi-Fi es insignificante. En un dispositivo móvil alimentado por batería, el coste está sobre todo en los despertares de la radio, no en los bytes: cada ping puede mantener el módem en un estado de alto consumo durante segundos. Para estos dispositivos, plantéate si realmente necesitas una conexión permanente o si es mejor despertar, publicar y desconectarse usando una sesión persistente.
Un punto de partida práctico
- Dispositivos conectados a la red eléctrica por Wi-Fi o Ethernet: 60 segundos.
- Dashboards y clientes de navegador sobre WebSocket: 30 segundos.
- Gateways móviles: de 60 a 120 segundos, y acórtalo si ves caídas inexplicables.
- Servicios backend en la misma región de nube: de 30 a 60 segundos.
- Nunca uses 0 en producción; elimina por completo la detección de conexiones muertas.
Cómo configurar el intervalo keep alive en clientes habituales
Puedes probar todos estos ejemplos contra el servidor MQTT público gratuito en broker.connectmq.com. Usa un client ID único y un prefijo de topic único, y recuerda que cualquiera puede leer el área pública: sirve para pruebas y prototipos, no para datos de producción.
mosquitto_sub y mosquitto_pub
# Suscríbete con un keep alive de 30 segundos y salida de depuración para ver PINGREQ/PINGRESP
mosquitto_sub -h broker.connectmq.com -p 1883 -i ka-demo-7f3a \
-k 30 -d -t 'connectmq/demo/7f3a/#'
Con -d verás líneas como Client ka-demo-7f3a sending PINGREQ y received PINGRESP cada 30 segundos mientras el topic esté en silencio.
Python (paho-mqtt 2.x)
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.subscribe("connectmq/demo/7f3a/#", qos=1)
def on_disconnect(client, userdata, flags, reason_code, properties):
print("Disconnected:", reason_code)
client = mqtt.Client(
mqtt.CallbackAPIVersion.VERSION2,
client_id="ka-python-7f3a",
protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
# keepalive es el tercer argumento, en segundos
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
paho envía PINGREQ automáticamente desde su bucle de red. Si bloqueas el bucle (por ejemplo, con un time.sleep largo dentro de un callback), los pings se detienen y el broker te desconectará tras 1,5x el intervalo.
Node.js (MQTT.js v5)
const mqtt = require("mqtt");
const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
clientId: "ka-node-7f3a",
protocolVersion: 5,
keepalive: 45, // segundos
reconnectPeriod: 5000, // ms entre intentos de reconexión
});
client.on("connect", () => console.log("connected"));
client.on("close", () => console.log("connection closed"));
client.on("error", (err) => console.error(err.message));
ESP32 (PubSubClient)
PubSubClient usa 15 segundos por defecto. Cámbialo antes de llamar a connect() con client.setKeepAlive(60);, y asegúrate de que client.loop() se ejecute con frecuencia en tu sketch, porque los pings solo se envían desde dentro de loop(). Las llamadas largas a delay() son el motivo más habitual por el que las placas ESP32 se desconectan a intervalos regulares. Un sketch de ESP32 bien estructurado usa un bucle no bloqueante con temporizadores basados en millis() para evitarlo.
Server Keep Alive en MQTT 5
MQTT 5 permite al broker imponerse a la petición del cliente. Si el CONNACK contiene la propiedad Server Keep Alive, el cliente debe usar ese valor en lugar del suyo. Los brokers lo hacen para imponer un intervalo mínimo o máximo en una plataforma compartida. La mayoría de las librerías lo aplican sin avisar, así que si notas pings a un ritmo distinto del que configuraste, registra las propiedades del CONNACK. En paho puedes imprimir properties en on_connect; MQTT.js las expone en el paquete connack que se pasa al evento connect.
Resolución de problemas de keep alive
Usa esta lista de comprobación cuando los clientes se desconecten a intervalos sospechosamente regulares:
- Mide el intervalo. Si las desconexiones ocurren aproximadamente 1,5x tu keep alive después de la última actividad, el cliente no está enviando pings. Busca un bucle de red bloqueado.
- Comprueba si hay una caída fija por inactividad. Si las caídas ocurren tras un número constante de minutos sea cual sea el keep alive, un NAT o un firewall está expirando la conexión. Baja el intervalo por debajo de ese valor.
- Busca client IDs duplicados. Dos clientes con el mismo ID se expulsan mutuamente, lo que parece un problema de keep alive pero no lo es. Consulta las buenas prácticas del client ID de MQTT.
- Vigila los callbacks de un solo hilo. El trabajo pesado dentro de
on_messageretrasa el PINGREQ. Lleva el procesamiento a un hilo worker o a una cola. - Confirma que los handshakes TLS se completan. En dispositivos limitados, una reconexión TLS lenta puede empujar el siguiente ping más allá del plazo.
- Activa el registro de depuración en tu librería y compara las marcas de tiempo del cliente con los eventos de conexión del broker.
En un broker de ConnectMQ también puedes observar $SYS/broker/connection/{clientId}/state para ver exactamente cuándo considera el broker que un cliente está conectado o desconectado, lo que facilita correlacionarlo con los logs de tus dispositivos. El cliente MQTT integrado en el navegador del portal es una forma rápida de suscribirse a ese topic sin instalar nada.
Keep alive, sesiones y Last Will trabajando juntos
El keep alive es una pieza de un diseño de fiabilidad más amplio. Un patrón de producción sensato tiene este aspecto:
- Un keep alive lo bastante corto como para adelantarse a los timeouts NAT y cumplir tu objetivo de detección.
- Un mensaje retenido "online" publicado al conectar, más un mensaje de will retenido "offline".
- Una sesión persistente para que no se pierdan los mensajes QoS 1 publicados mientras el dispositivo se reconecta.
- Backoff exponencial en la reconexión, para que un reinicio del broker no se convierta en una estampida.
El tutorial de MQTT cubre estos componentes desde el principio si quieres el contexto completo.
Empieza con ConnectMQ
ConnectMQ es un broker MQTT gestionado que admite MQTT 3.1.1 y 5.0 sobre TCP, TLS, WebSocket y WebSocket seguro, así que puedes probar cualquier estrategia de keep alive en los mismos endpoints que usarás en producción. Cuando estés listo para ir más allá del servidor público, crea un broker Serverless gratuito sin tarjeta de crédito, copia las credenciales generadas y observa el estado de las conexiones en directo en el portal. Si todavía estás comparando opciones, nuestra guía para elegir un broker MQTT en la nube repasa las ventajas e inconvenientes.
Preguntas frecuentes
¿Cuál es un buen intervalo keep alive de MQTT por defecto?
60 segundos es un buen valor por defecto para la mayoría de los dispositivos conectados a la red eléctrica. Redúcelo a 15 o 30 segundos si necesitas detectar antes la desconexión, o si un dispositivo NAT del trayecto corta antes las conexiones inactivas.
¿Cualquier paquete MQTT reinicia el temporizador de keep alive?
Sí. Cualquier paquete de control que envíe el cliente, incluidos PUBLISH y PUBACK, cuenta como actividad. PINGREQ solo se envía cuando el cliente ha estado inactivo durante todo el intervalo.
¿Qué pasa si pongo el keep alive a 0?
El keep alive queda desactivado, de modo que el broker nunca cierra por sí mismo una conexión silenciosa. Los dispositivos caídos pueden aparecer como conectados indefinidamente y sus mensajes de will quizá nunca se envíen, así que evita el 0 en producción.
¿Por qué mi cliente se desconecta exactamente cada pocos minutos?
Un intervalo constante, independiente de tu configuración de keep alive, suele indicar un timeout de inactividad de un NAT o un firewall. Configura el keep alive por debajo de ese timeout para que los pings mantengan vivo el mapeo.
¿Puede el broker cambiar mi valor de keep alive?
En MQTT 5, sí. El broker puede devolver la propiedad Server Keep Alive en el CONNACK, y el cliente debe usar ese valor en lugar del que solicitó.



