← All Posts

MQTT vs HTTP for IoT: Which Protocol Should You Use

HTTP and MQTT are the two protocols that come up first whenever someone designs an IoT backend. HTTP is the default — every device speaks it, every firewall allows it, every developer understands it. MQTT is the purpose-built alternative — a lightweight publish/subscribe protocol designed in 1999 for oil pipelines and now the de facto standard for telemetry fan-out. They are not rivals. They solve different problems, and most production systems use both. Whether you are streaming sensor data from a fleet or wiring up an MQTT broker on your Mac for device testing, the trade-off looks the same.

This comparison breaks down where each protocol wins, where it loses, and how to decide. We will cover the connection model, bandwidth, latency, power, NAT traversal, reliability, and the real numbers behind the trade-offs. By the end you should know which protocol fits your workload and where the boundary sits when you use both.

The Core Model

HTTP is request/response. A client opens a TCP connection (usually port 80 for plaintext or 443 for TLS), sends a request with method, path, and headers, and the server responds. The protocol is stateless — each request carries everything the server needs, and the connection can close afterwards. HTTP keep-alive reuses the TCP socket across requests, but the model is still client-initiated request/response.

MQTT is publish/subscribe. A client opens one persistent TCP connection to a broker (port 1883 plaintext, 8883 for TLS), sends a CONNECT packet, and the broker responds with a CONNACK. The client then subscribes to topics and publishes messages. The broker forwards each published message to every subscribed client. The connection stays open for the lifetime of the session, kept alive by lightweight PINGREQ/PINGRESP packets. State — subscriptions, queued messages, session — lives in the broker.

Connection Model

The single biggest difference is how each protocol treats the connection.

  • HTTP: Each request opens a context, sends headers and body, reads the response, and either closes or returns the socket to a keep-alive pool. There is no server-initiated message delivery. To learn that a new command exists, the client must poll — send another request and ask.
  • MQTT: One TCP connection, opened once and held open for hours or days. After the initial handshake, the broker pushes messages to the client the instant they are published. The keepalive is a single 2-byte PINGREQ every (typically) 30–60 seconds, with a 2-byte PINGRESP reply.

For a device that needs to receive commands, this is the difference between "wake up every 5 seconds and ask the server if there is anything new" (HTTP) and "stay connected and the server will tell you" (MQTT). The first burns cycles and radio time. The second costs almost nothing while idle.

Bandwidth and Header Size

The wire overhead per message is where the numbers diverge sharply.

  • HTTP: A minimal HTTP/1.1 request to POST a 1-byte sensor reading looks like POST /telemetry HTTP/1.1\r\nHost: api.example.com\r\nContent-Type: application/json\r\nContent-Length: 13\r\n\r\n{"v":42}. That is roughly 110–130 bytes of header plus a 13-byte JSON body — call it ~120–140 bytes on the wire to send one byte of information. TLS adds its own handshake overhead at the start of the connection.
  • MQTT: A PUBLISH packet has a 2-byte fixed header (packet type + flags, plus remaining-length), a small variable header for the topic name, and the payload. Publishing 42 to s/t is ~7 bytes total: 2 bytes fixed header, 2 bytes topic length, 3 bytes topic, 2 bytes payload. With a slightly longer topic like plant/line3/cellA/temp the total is ~25 bytes — still a fraction of the HTTP request.

At scale, this ratio dominates. 10,000 devices each reporting once per minute over HTTP send ~1.4 MB/minute of headers alone. Over MQTT the same traffic is ~70–250 KB/minute — a 5–20x reduction on a link where bandwidth is the budget.

Quick Comparison

Factor
MQTT
HTTP
Model
Publish/subscribe
Request/response
Default ports
1883 / 8883 (TLS)
80 / 443 (TLS)
Header size
~2 bytes fixed
Hundreds of bytes
Direction
Server pushes
Client polls
Connection
One persistent TCP
Per request / keep-alive
Power for idle devices
Low (infrequent PINGREQ)
High (polling)
NAT-friendly
Yes (outbound, then push)
Yes, but needs polling
Delivery guarantee
QoS 0 / 1 / 2 built in
None (manual retry)

Latency: Push vs Poll

For event-driven workloads, latency is determined by how quickly a message reaches the client after it is published. With MQTT, that latency is the one-way network trip from publisher to broker plus broker to subscriber — typically a few milliseconds on a LAN, tens of milliseconds over the open internet.

With HTTP polling, the average latency is roughly half the polling interval. Poll every 5 seconds and the average wait for a new command is 2.5 seconds, with a worst case of 5 seconds. To match MQTT's millisecond latency you would need to poll at 10–50 ms intervals, which would saturate the radio, drain the battery, and hammer the server. Long polling and Server-Sent Events narrow the gap, but they are workarounds for a protocol that was never designed for push.

Power: Why Battery Devices Prefer MQTT

On a constrained device the radio is the largest single power consumer. The most expensive thing the device can do is wake the radio, associate, and transmit. So the cheapest thing it can do is sleep.

MQTT keeps one connection open and sends a tiny PINGREQ every keepalive interval. Between keepalives the radio can sleep. A device reporting every 10 minutes with a 60-second keepalive transmits for a few hundred milliseconds per cycle. An HTTP device polled every 5 seconds for commands never sleeps — it spends most of its energy on headers asking "anything new?" and the answer is almost always "no."

For mains-powered gateways the difference does not matter. For battery-powered sensors on a multi-year coin cell, MQTT can be the difference between a 1-year and a 5-year battery life. The exact ratio depends on the radio (LoRaWAN, NB-IoT, BLE, Wi-Fi), but the direction is always the same: less overhead, less airtime, longer life.

NAT and Firewalls

Almost every IoT device sits behind NAT — home routers, cellular carriers, industrial cell modems. NAT allows outbound connections but blocks inbound ones. This shapes protocol choice.

  • MQTT: The client opens one outbound TCP connection to the broker on port 1883/8883. The NAT state keeps that connection alive. The broker then pushes messages inbound over the same socket. No inbound ports, no port forwarding, no special firewall rules. This works from behind virtually any NAT.
  • HTTP: Outbound works the same way, but to receive a command the device must either poll (outbound request → response) or the server must reach the device inbound (webhooks), which NAT blocks. Polling is the workable default; webhooks require the device to expose a public address, which is rarely possible behind carrier-grade NAT.

This is why MQTT and similar broker protocols have become the default for multi-site industrial deployments: one outbound connection per site, and the central system can push to every site without any site needing a public IP.

Reliability and Delivery Guarantees

MQTT builds delivery guarantees into the protocol. QoS 0, 1, and 2 give you at-most-once, at-least-once, and exactly-once delivery on a per-message basis, negotiated between publisher, broker, and subscriber. The broker stores queued messages for disconnected clients with persistent sessions, and the Last Will and Testament feature lets the broker notify other clients when a device drops off unexpectedly.

HTTP has no equivalent. A POST that times out might have been delivered or might not — the client cannot tell. To get a delivery guarantee you build your own retry layer: idempotency keys, deduplication tables, at-least-once retries with exponential backoff. That machinery is not free, and it is usually where homegrown HTTP-based IoT backends accumulate bugs.

Rule of thumb: if your workload is one-to-many fan-out (many subscribers consuming the same telemetry), constrained devices on bandwidth or battery, or any case where the server needs to push to clients behind NAT — use MQTT. If your workload is fetching a resource by URL, calling a REST API, uploading a file, or serving a human-facing page — use HTTP.

When HTTP Wins

  • REST configuration APIs. Fetching a device's current configuration, updating a user account, listing assets — request/response is the right shape, and the HTTP ecosystem (auth, caching, gateways) is mature.
  • File uploads and bulk transfers. Firmware images, log bundles, certificate requests. HTTP handles large bodies and streaming uploads cleanly; MQTT v5 can but is not the natural fit.
  • Webhooks and OAuth. Token exchange, certificate enrollment (EST/ACME), third-party callbacks all assume HTTP verbs and URLs.
  • Human-facing web UI. Browsers speak HTTP natively. A dashboard backend that exposes REST to the browser and speaks MQTT internally to the broker is the standard pattern.
  • One-shot commands with a response. "Set setpoint to 75" where you need an immediate confirmation and a return value fits HTTP's synchronous shape better than MQTT's fire-and-subscribe.

When MQTT Wins

  • Telemetry fan-out. One sensor reading consumed by a dashboard, a database writer, an alarm engine, and an analytics service simultaneously. One publish, many subscribers, broker does the fan-out.
  • Command and control to devices behind NAT. Push a setpoint to a field device without opening inbound ports or polling.
  • Multi-site and industrial data pipelines. Thousands of devices publishing to a central broker; consumers subscribe to the topics they care about. See topic design best practices for how to structure that namespace.
  • Constrained devices. Microcontrollers, low-bandwidth cellular (NB-IoT, LTE-M), satellite links. The 2-byte header and persistent connection matter.
  • Low-latency push. Real-time UIs, presence, alarms, status updates. The broker pushes; there is no polling interval to halve.

Coexistence: Use Both

The mature answer in almost every real IoT system is to use both protocols for what each is good at:

  • MQTT for telemetry streaming, event fan-out, command/control, and anything that flows device-to-cloud or cloud-to-device as a stream.
  • HTTP for the configuration UI, REST APIs, file and firmware uploads, certificate enrollment, and OAuth/token exchange.

A typical device firmware stack speaks both: an MQTT client for telemetry and commands, and an HTTP client for fetching configuration, downloading firmware updates, and enrolling certificates. The two protocols share the same network interface and do not conflict. A backend that ingests MQTT and exposes a REST API to the browser is the normal shape, and it is exactly what an industrial protocol comparison shows when you map it out.

For local development and protocol debugging, a tool like MacTools MQTT Explorer lets you connect to a broker, browse the topic tree, and watch real payloads arrive — the fastest way to confirm that your MQTT path is actually carrying the telemetry before you wire it into the HTTP side of the stack.

Frequently Asked Questions

Is MQTT faster than HTTP for IoT?

For push-based telemetry and event fan-out, yes. MQTT holds a single persistent TCP connection and pushes messages with a 2-byte fixed header, so latency is the one-way network trip. HTTP request/response requires polling, and each request carries hundreds of bytes of headers, so average latency is roughly half the polling interval plus round-trip time.

Can MQTT and HTTP be used together?

Yes, and most production IoT systems do exactly that. Use MQTT for high-frequency telemetry, real-time events, and command and control, and use HTTP for REST configuration APIs, file uploads, certificate enrollment, OAuth token exchange, and human-facing web UIs. A device can easily speak both protocols over the same network stack.

Why is MQTT more battery-friendly than HTTP for constrained devices?

MQTT opens one TCP connection and keeps it alive with infrequent PINGREQ packets, often every 30 to 60 seconds, so the radio can sleep between pushes. HTTP polling forces the device to re-establish context, send large headers, and check for new data at short intervals, which keeps the radio on and drains batteries many times faster.

Does HTTP work behind NAT for IoT devices?

Only with polling or webhooks. HTTP is request and response, so a device behind NAT must poll the server to learn of new commands, or the server must be reachable inbound for webhooks. MQTT clients initiate one outbound connection to the broker and then receive pushes over it, which works cleanly through NAT and firewalls without inbound ports.

MQTT Explorer for macOS

MacTools MQTT Explorer — built-in broker, publish/subscribe, topic tree browser, message history. Inspect real MQTT traffic side by side with your HTTP API. $14.99 one-time.

Get MacTools MQTT Explorer

Related: Full SCADA System

Need continuous MQTT monitoring with dashboards, alarms, and trending? Voltrus SCADA supports MQTT, Modbus TCP/RTU, OPC-UA, Siemens S7, BACnet, DNP3, and more. Lifetime license from $249.

Further Reading