When we built our device management agent, one of the first things we had to decide was how a device finds out it has work to do.
The usual answer is polling, where every device asks the server on a timer whether there’s anything for it. It’s simple and it’s easy to debug, but almost all of it is wasted. Ten thousand devices checking in once a minute works out to about 170 requests a second all day long, and nearly every answer is no. You can stretch the interval to cut the load, but then a technician clicks a button and waits fifteen minutes to see if it worked. Our fleet is tens of thousands of Windows and Mac devices, so neither option was going to work.
MQTT turns that around. Each device keeps a connection open to a broker and listens, and when the server has something it publishes a message and the device hears about it right away. When nothing is going on, the only traffic is a keepalive.
A lot of people use MQTT to carry the actual command, and I understand why, because it works fine in a demo. It gets harder once commands get bigger, or you need to cancel one before it lands, or you need a record of exactly when a device picked it up. At that point you’re rebuilding pieces of HTTP on top of a message broker.
We went the other way and made the MQTT message empty. It’s only a signal to go check. The device then fetches its pending commands over HTTPS with its own token, the same way it would if it were polling. Commands sit in the database until they’re picked up, so they can be changed or cancelled, and every fetch gets logged. Retries and error handling are ordinary HTTP.
Keeping the message empty also settled how to handle broker credentials. All of our agents share the same broker login, stored encrypted on each device. Giving every device its own broker account would have meant provisioning and rotating thousands of credentials in a second system, and since the wake-up message doesn’t carry anything, the worst a forged one can do is make a device check in early.
Each device listens on its own topic, a topic for its site, and one for the whole fleet, so a single publish can wake one laptop or every device we manage. The per-device topic is a SHA-256 hash of the device’s token so nobody can guess it.
We still poll underneath all of this, once an hour instead of once a minute, because connections drop and some networks don’t like long-lived connections. If MQTT is down, commands still get there, only slower.
The fallback caused a problem we didn’t expect. An agent that can’t log in to the broker drops to hourly polling and keeps working, so from the outside it looks healthy and you only notice because commands are slow. We added MQTT connection status per device to the dashboard so we can actually see it.
For a few hundred devices I’d just poll. Push starts paying for itself somewhere in the thousands, and you need someone keeping an eye on the broker once you have it.



