MQTT Fundamentals

MQTT Will Delay Interval: How to Avoid False Offline Alerts

A device that drops Wi-Fi for three seconds should not page your on-call engineer. MQTT 5's will delay interval holds the Last Will message back long enough for a quick reconnect.

MQTT will delay interval illustration with a timer holding back an offline Last Will message while an IoT device quickly reconnects
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

The MQTT will delay interval is an MQTT 5 property that tells the broker to wait a number of seconds before publishing a client's Last Will message, and to cancel it entirely if the client reconnects in time. In this article you will see how it suppresses noisy offline alerts caused by brief network blips, how it interacts with session expiry, and how to configure it in mosquitto, Python and Node.js.

The Problem: Flapping Offline Alerts

The Last Will and Testament is MQTT's built-in way to announce that a client vanished. The client registers a will message at connect time, typically a retained offline on a status topic, and the broker publishes it if the connection ends without a clean DISCONNECT.

In MQTT 3.1.1 the will is published as soon as the broker detects the failure. On real networks, that is noisy:

  • A Wi-Fi access point roams a device to another AP and the TCP connection resets.
  • A cellular modem renegotiates and the device is back within seconds.
  • A gateway restarts its MQTT process after a configuration change.

Each case produces an offline message followed moments later by online. Dashboards flicker, alert rules fire, and operators learn to ignore the alerts, which is worse than having none.

How the MQTT Will Delay Interval Works

MQTT 5 adds the Will Delay Interval, a four-byte property in seconds attached to the will message in CONNECT. When the network connection closes abnormally:

  1. The broker starts a timer for the will delay interval.
  2. If the same client reconnects to the same session before the timer expires, the will is not published.
  3. If the timer expires first, the will is published as usual.
  4. If the session ends first (because the session expiry interval elapses), the will is published at that moment.

The default is 0, which reproduces the 3.1.1 behaviour of immediate publication.

The Rule Everyone Misses: Session Expiry

The will is published when the delay passes or the session ends, whichever comes first. If the client connects with a session expiry interval of 0, the session ends the instant the connection closes, so the will goes out immediately and your delay has no effect.

Will delay Session expiry What you get
0 any Immediate will on abnormal disconnect
30 s 0 Immediate will (session ended first)
30 s 60 s Will after 30 s unless the client reconnects
30 s 10 s Will after 10 s (session ended first)
300 s 3600 s Will after 5 minutes unless the client reconnects

So to use will delay, always set a session expiry interval at least as long as the delay, and reconnect with Clean Start set to false so the broker treats the new connection as the same session. Details are in MQTT 5 clean start and session expiry interval.

Keep Alive Adds to the Total

The timer only starts once the broker notices the connection is gone. If a device loses power, detection takes up to 1.5 times the keep alive. With a 60 second keep alive and a 30 second will delay, worst-case time to an offline message is about two minutes. Budget both together; see choosing an MQTT keep alive interval.

Choosing a Will Delay Value

Pick the shortest delay that covers your normal reconnect time.

  • Wi-Fi devices with fast reconnect logic: 10 to 30 seconds.
  • Cellular devices: 30 to 120 seconds; modem re-registration is slower.
  • Gateways that restart services during updates: slightly longer than a typical restart.
  • Safety-relevant equipment: keep it short, or 0. A delayed alarm can cost more than a false one.

A practical test: log the time between disconnect and reconnect for a week of real operation and choose a value just above the bulk of those gaps.

Configuring Will Delay in Code

All examples use the public MQTT test broker at broker.connectmq.com. Replace w3d8 with your own random string, and remember the public area is readable by anyone.

mosquitto_sub as a Simulated Device

mosquitto_sub -h broker.connectmq.com -p 1883 -V mqttv5 \
  -i willdelay-dev-w3d8 -c -x 120 \
  --will-topic 'connectmq/demo/w3d8/status' \
  --will-payload 'offline' --will-qos 1 --will-retain \
  -D will will-delay-interval 30 \
  -t 'connectmq/demo/w3d8/cmd'

In another terminal, watch the status topic:

mosquitto_sub -h broker.connectmq.com -p 1883 -i willdelay-watch-w3d8 \
  -v -t 'connectmq/demo/w3d8/status'

Ctrl+C on mosquitto_sub sends a clean DISCONNECT, which never triggers a will. To simulate a real failure, kill the process instead (for example kill -9 on its process ID, or unplug the network). Then try two cases: restart the device command within 30 seconds and no offline appears; wait longer and it does.

Python (paho-mqtt 2.x)

import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

STATUS = "connectmq/demo/w3d8/status"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id="willdelay-py-w3d8",
                     protocol=mqtt.MQTTv5)

will_props = Properties(PacketTypes.WILLMESSAGE)
will_props.WillDelayInterval = 30          # seconds
client.will_set(STATUS, payload="offline", qos=1, retain=True,
                properties=will_props)

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    # Announce we are online (overwrites a retained "offline")
    client.publish(STATUS, "online", qos=1, retain=True)

client.on_connect = on_connect

connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 120  # must be >= will delay

client.connect("broker.connectmq.com", 1883, keepalive=30,
               clean_start=False, properties=connect_props)
client.loop_forever()

Node.js (MQTT.js v5)

const mqtt = require("mqtt");
const STATUS = "connectmq/demo/w3d8/status";

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "willdelay-node-w3d8",
  protocolVersion: 5,
  clean: false,
  keepalive: 30,
  properties: { sessionExpiryInterval: 120 },
  will: {
    topic: STATUS,
    payload: Buffer.from("offline"),
    qos: 1,
    retain: true,
    properties: { willDelayInterval: 30 },
  },
});

client.on("connect", () => {
  client.publish(STATUS, "online", { qos: 1, retain: true });
});

A Complete Online/Offline Pattern

Will delay works best as part of a consistent presence design:

  1. Register a retained offline will with a will delay and matching session expiry.
  2. Publish a retained online immediately after every successful connect.
  3. Before a planned shutdown, publish a retained offline yourself, then disconnect cleanly.
  4. Let dashboards and alert rules read only the retained status topic.
  5. Optionally add a timestamp or reason in a JSON payload so operators can see why a device went offline.

More presence patterns are covered in MQTT device online status. On a ConnectMQ broker you can also cross-check with the $SYS/broker/connection/{clientId}/state topic, which reflects the broker's view of the raw connection rather than your application-level status.

Will Delay Versus Debouncing in the Application

Before MQTT 5, teams solved flapping by debouncing in the consumer: a dashboard or alerting service waited N seconds after an offline message and only raised an alarm if no online followed. That still works, but every consumer has to implement the same logic, and each one may pick a different window. Will delay moves the decision into the broker, so every subscriber sees the same, already-filtered status stream. The trade-off is that the delay is set per client at connect time, so changing it means updating device configuration rather than one backend service.

Troubleshooting Will Delay

  • Will still fires immediately: session expiry is 0 or shorter than the will delay, or you are connecting with MQTT 3.1.1.
  • Will fires even though the device reconnected quickly: the device reconnected with Clean Start true or a different client ID, so it was a new session.
  • Will never fires: the client disconnected cleanly, or the delay is longer than you waited. Remember to add keep alive detection time.
  • Stale offline shown after reconnect: publish a retained online on every connect, not just the first one.

New to these concepts? The MQTT tutorial explains wills, sessions and retained messages from the start.

Build Reliable Device Status on ConnectMQ

ConnectMQ is a managed MQTT broker with full MQTT 5.0 support, including will properties, session expiry and retained messages. Its portal adds threshold alert rules and an alerts log, so cleaner status data at the protocol level means fewer noisy alerts from the rules you build on it. Start free on the Serverless plan, no credit card needed, connect with YOUR_USERNAME, YOUR_PASSWORD and YOUR_CLIENT_ID, and test your will delay settings on your own broker.

Frequently Asked Questions

What is the default MQTT will delay interval?

The default is 0 seconds, which means the will message is published as soon as the broker detects an abnormal disconnect, just like in MQTT 3.1.1.

Why does my will message ignore the delay?

Most often the session expiry interval is 0 or shorter than the will delay. The broker publishes the will when the session ends, so the session must last at least as long as the delay.

Is will delay available in MQTT 3.1.1?

No. It is an MQTT 5 feature. With MQTT 3.1.1 you would have to debounce offline events in the consuming application instead.

Does a clean disconnect trigger the will message?

No. A normal DISCONNECT discards the will. In MQTT 5 a client can deliberately request the will by disconnecting with reason code 0x04 (Disconnect with Will Message).

Related articles

Why Your MQTT Client Keeps Disconnecting (and How to Fix It)

Reconnect loops are one of the most common MQTT problems. Learn the five usual causes, from duplicate client IDs to keep alive timeouts and oversized packets, and follow a diagnosis flow that pinpoints yours.

8 min read

Who Invented MQTT? The History from Oil Pipelines to IoT

MQTT was invented in 1999 by Andy Stanford-Clark of IBM and Arlen Nipper of Arcom to monitor oil pipelines over satellite. Follow its path to open source, OASIS, ISO and today's managed cloud brokers.

7 min read

MQTT Maximum Message Size: Limits and Large Payload Strategies

MQTT can technically carry a 256 MB packet, but brokers, client libraries and devices impose far lower limits. Learn where the real limits are, what happens when you exceed them, and how to send large payloads.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.