If you are building something that needs to move data between clients and servers in real time — device telemetry, live dashboards, push notifications, chat, multiplayer state — you have several protocols to choose from, and HTTP and MQTT are two of the most common. On paper they look like alternatives; in practice they solve different problems well, and the real question is not “which is better” but “which fits my traffic pattern.”
This article compares HTTP and MQTT specifically for real-time messaging use cases, and walks through the HTTP-based patterns that people use when they want push-style behavior (long polling, Server-Sent Events, WebSockets) alongside MQTT itself. It is honest about the tradeoffs and specific about which pattern to reach for in which situation. It leans toward MQTT for the cases where MQTT genuinely wins, and toward HTTP-based approaches where they are the better fit — because you learn nothing from an article that pretends one protocol is always right.
Table of Contents
Which pattern at a glance
| Approach | Model | Direction | Overhead per message | Typical use |
|---|---|---|---|---|
| HTTP request/response (polling) | Client asks, server answers | Client-initiated only | High (headers, connect per request) | REST APIs, occasional data fetch |
| HTTP long polling | Client asks, server holds until data or timeout | Server-to-client push (simulated) | High per cycle | Legacy push notification, chat |
| Server-Sent Events (SSE) | Long-lived HTTP response streaming events | Server → client only | Low per event, high initial setup | Live news feeds, one-way updates |
| WebSockets | Long-lived, full-duplex over TCP after HTTP upgrade | Bidirectional | Low per message | Chat, multiplayer, custom protocols |
| MQTT | Long-lived pub/sub via a broker | Bidirectional | Very low (2-byte fixed header minimum) | IoT telemetry, device fleets, event distribution |
The rest of this article explains why the differences matter and when each approach earns its place.
How HTTP-based messaging works, briefly
HTTP is a request/response protocol, and in its plain form, that is exactly what it does: a client opens a TCP connection, sends a request with headers, gets a response with headers, and the connection may or may not stay open for the next request. This works beautifully for the web — pages, APIs, uploads, downloads — where the client always initiates and the server always responds.
Real-time messaging is a poor fit for that model, because in real time, the server often has something to say first. A device that just came online, a message that arrived from another user, a stock price that just moved — all of these need to reach the client without the client having asked. Plain HTTP does not support this. The client has to ask first.
Over the years, HTTP-based real-time approaches have grown to work around this:
Short polling — the client repeatedly asks “anything new?” every few seconds. Simple, but wasteful: most requests come back empty, latency is bounded by the poll interval, and the overhead is enormous when multiplied across many clients.
Long polling — the client asks and the server holds the connection open (up to some timeout) until there is something to send. Better latency than short polling, but still one full request/response cycle per message, and every server-side event immediately triggers a new client request to receive the next one.
Server-Sent Events (SSE) — the client opens a normal HTTP request and the server responds with a long-lived, streaming response containing a series of events. One connection, many pushes, low overhead per push. But it is one-way (server to client only) and layered on HTTP, so it still carries some HTTP baggage.
WebSockets — after an initial HTTP upgrade handshake, the connection becomes a full-duplex binary channel between the client and the server. Both sides can send at any time, with low overhead per message. This is what most modern real-time web applications use.
Each of these is a workaround for the fact that HTTP was not built for what we are trying to do with it here. They work, and in many cases they are the right choice — but they are workarounds, and understanding that helps clarify what MQTT is offering as a first-class alternative.
How MQTT works, briefly
MQTT is a publish/subscribe protocol built specifically for lightweight, long-lived, bidirectional messaging over unreliable networks. Unlike HTTP, MQTT is not request/response. A client connects to a broker (the central hub), stays connected, and either publishes messages to topics or subscribes to topics to receive messages. The broker routes messages between publishers and subscribers.
The key distinction is that MQTT was designed for exactly the problem the HTTP-based real-time patterns are working around. A long-lived, low-overhead, bidirectional connection is the default in MQTT, not a workaround. The protocol adds Quality of Service levels (at-most-once, at-least-once, exactly-once), retained messages (last known value on a topic), Last Will and Testament (published when a client disconnects unexpectedly), and persistent sessions (queued messages for offline clients). All of these are built in.
MQTT is covered in detail in the other articles in this category, including the flagship What Is MQTT article, so this comparison focuses on how it stacks up against the HTTP-based options.
The dimensions that actually matter
A useful comparison names the axes worth caring about, not just the surface features. For real-time messaging, five dimensions dominate the choice.
Direction of traffic
The single most important question is whether the server needs to push to the client, or whether the client always initiates. If it’s always client-initiated (“give me the current price when I ask”), plain HTTP is fine. If the server needs to reach the client on its own schedule (“here is an event that just happened”), you need something more.
- HTTP request/response — client-initiated only.
- Long polling — simulates server push, one message at a time.
- SSE — server push, one direction.
- WebSockets — bidirectional.
- MQTT — bidirectional, and inherently many-to-many because the broker fans out messages to every subscriber.
For pure server-to-client streams (live scores, real-time news, log tails), SSE is often the sweetest spot. For bidirectional real-time (chat, collaboration, multiplayer), WebSockets or MQTT. For device telemetry with many devices reporting to central systems and receiving commands back, MQTT is designed for exactly this.
Overhead per message
HTTP is a text protocol with substantial header overhead — cookies, user-agent strings, custom headers, content-type, and so on can easily add hundreds of bytes to every request and every response. Even with HTTP/2 header compression, the baseline is meaningful compared to what MQTT sends. WebSockets add only a small framing overhead once established. MQTT’s fixed header is as small as two bytes.
For a single message every few minutes, this does not matter. For a device publishing a sensor reading every second, a client streaming rapid updates, or a fleet of thousands of devices sending frequent small messages, the overhead adds up quickly. MQTT was designed to minimize this cost per message, and it is the reason MQTT often wins for constrained devices and metered networks. A cellular-connected sensor sending 100 bytes of payload per minute over MQTT uses noticeably less bandwidth over a month than the same sensor doing the same thing over HTTP.
Scale (many clients)
How many concurrent connections can one server handle? For HTTP request/response, connections are typically short-lived, so a single server can handle a large number of requests per second even if the concurrent connection count is modest. For long-lived approaches — long polling, SSE, WebSockets, MQTT — you are holding open one persistent connection per client, and the number of concurrent connections is what matters.
At the level of “1,000 concurrent connections,” any of these can work. At “100,000 concurrent connections,” HTTP-based approaches start to strain default configurations, and both WebSockets and MQTT are commonly used at this scale. At “1 million or 100 million concurrent connections,” MQTT is unusually well suited: the brokers that support this scale (EMQX, HiveMQ Enterprise, and others) are designed for it, and their masterless clustering handles fleet-scale IoT. WebSockets at this scale exist but require serious infrastructure engineering.
Delivery guarantees
What happens when the network drops in the middle of a message? Do you get the message eventually, get it maybe, or lose it?
- HTTP — the request either succeeds (you know) or fails (you know). Retry is up to the application. There is no built-in “at least once” or “exactly once” guarantee.
- SSE — automatic reconnection with a Last-Event-ID header lets the server resume from where it left off, if the server implements it. Reasonable delivery guarantees are possible but require server-side work.
- WebSockets — no built-in delivery guarantee. The connection either delivers or breaks. Retry, ordering, and idempotency are application-level concerns.
- MQTT — three Quality of Service levels: 0 (at most once), 1 (at least once), 2 (exactly once). Built into the protocol. Delivery guarantees survive reconnects when combined with persistent sessions.
For real-time messaging where you cannot afford to lose messages (financial data, safety-critical commands, ordering-sensitive events), MQTT’s QoS levels are a significant advantage. For messaging where “best effort” is acceptable (live dashboards, non-critical event streams), the difference matters less.
Firewall traversal and infrastructure
Both HTTP and MQTT can traverse most firewalls, but the details differ. HTTP-based approaches use ports 80 and 443, which are open almost everywhere; WebSockets use the same ports after an upgrade handshake, so they too traverse most firewalls (see the MQTT Over WebSockets article). Plain MQTT uses ports 1883 (plain) and 8883 (TLS), which are often blocked in enterprise or public networks — the workaround is MQTT over WebSockets on port 443, which behaves like HTTPS from a firewall’s perspective.
For deployments where you can control the network path, plain MQTT is more efficient. For deployments where clients live in restrictive networks (mobile devices, corporate networks, hotel Wi-Fi), MQTT over WebSockets or HTTP-based approaches are more likely to reach the server without special configuration.
HTTP wins here
Some real-time-adjacent use cases genuinely fit HTTP better, and it is worth naming them plainly:
Occasional data fetch. If a client only needs data once every few minutes, and the data is not time-critical to the second, plain HTTP polling is dead simple and requires no long-lived infrastructure. Do not build a broker to solve a problem you can solve with a single GET request.
Public-facing REST APIs. If your API is meant for third-party developers, HTTP is the universal language. Any tool, any language, any environment can call it. MQTT requires MQTT libraries and MQTT-aware infrastructure. For an API that many external teams will consume, HTTP has network effects that MQTT does not.
One-way server-to-browser feeds where reliability is not critical. SSE was designed for this. Live sports scores, real-time news, notifications ticking down a page — SSE is simpler than MQTT for these cases and does not require running a broker.
Static-content distribution. HTTP/2 and HTTP/3 are excellent for delivering many small resources concurrently, which is what web pages need. MQTT is a messaging protocol, not a content-delivery mechanism. Do not put HTML behind MQTT.
Highly asymmetric, client-initiated bulk data. Uploads, downloads, and pagination-heavy workloads fit HTTP’s request/response model naturally. MQTT can carry these, but so can HTTP, and HTTP is already there.
MQTT wins here
The situations where MQTT is the clearly better real-time messaging choice fall into a few categories:
Many devices, many messages, small payloads. Device fleets sending frequent, small readings are exactly what MQTT was built for. The per-message overhead is dramatically lower than HTTP, the persistent connection is one-time setup, and the pub/sub model naturally handles fan-out to multiple consumers (a dashboard, a historian, an alerting system) without the publisher doing any extra work.
Unreliable networks. MQTT’s Quality of Service levels, keep-alive detection of half-open connections, Last Will messages, and persistent sessions are all built for networks that drop and come back. HTTP-based approaches on the same networks either need retry logic layered on the application, or accept losing messages when connections break.
Fan-out from one publisher to many subscribers. In pub/sub, one publisher can reach many subscribers through the broker with a single publish. In HTTP-based approaches, either the publisher explicitly knows and reaches every subscriber (which does not scale), or a message-fan-out layer sits in the middle (which is essentially rebuilding a broker). If your messaging pattern is naturally one-to-many, MQTT gives you that for free.
Bidirectional device communication. A device that publishes telemetry and subscribes to commands is the canonical MQTT use case. Both directions work over the same long-lived connection with the same low overhead. Implementing the equivalent over WebSockets is feasible but requires designing the framing and delivery yourself, whereas MQTT gives you the structure for free.
Persistent-connection efficiency at scale. A single MQTT broker can handle tens of thousands to millions of concurrent connections, depending on the broker. The connection model is designed for it. WebSockets can reach similar scales, but the messaging semantics (fan-out, delivery guarantees, session handling) are yours to build; MQTT gives them to you.
Constrained devices. Microcontrollers, battery-powered sensors, cellular-connected devices — anything where CPU, memory, or battery are scarce — benefit from MQTT’s small footprint. A minimal MQTT client library is a few kilobytes; a minimal HTTP + WebSocket + retry-logic implementation is much larger.
Choosing between the HTTP-based real-time options
If you have decided against MQTT (for genuinely good reasons — a purely web-facing application, a small deployment where MQTT is overkill, an existing HTTP infrastructure you cannot deviate from), the HTTP-based options each have a specific place:
Short polling — do this only if updates are rare and latency is not critical. It is simple to build and terrible at scale.
Long polling — a step up from short polling for legacy environments that cannot upgrade to SSE or WebSockets. Falling out of favor as browser and server support for the alternatives has stabilized.
Server-Sent Events (SSE) — the right choice for one-way, server-to-client streams over HTTP. Simple, native browser support (EventSource), automatic reconnection, and low overhead once established. Use SSE for feeds where the client does not need to send anything of consequence back.
WebSockets — the right choice for bidirectional real-time messaging where MQTT’s pub/sub semantics are overkill or the messaging is naturally point-to-point. Chat between two users, a game session between a client and a server, custom protocols where the framing is application-defined. WebSockets are lower-level than MQTT: you get a bidirectional binary channel and no message-routing, no delivery guarantees, no fan-out. Everything on top is up to you.
The general shape of the decision, if you have to choose among the HTTP-based options, is:
- One-way from server → client → SSE.
- Bidirectional but application-defined framing → WebSockets.
- Client-initiated → plain HTTP.
- Legacy compatibility → long polling.
If any of these get bent to serve a pub/sub, fan-out, or delivery-guaranteed use case, that is usually the point where MQTT starts to make more sense.
HTTP vs MQTT for common real-time scenarios
Rather than list features abstractly, it helps to walk through specific scenarios and name the pick for each.
Device telemetry from a fleet of IoT sensors. MQTT. This is the exact scenario MQTT was designed for. Low overhead per reading, bidirectional so you can send commands back, delivery guarantees when needed, persistent sessions for intermittent connectivity. No serious contest.
Real-time chat between users in a web app. WebSockets, unless you also need the pub/sub features MQTT provides (group chats with server-side history, presence updates fanning out to many clients, offline message queuing). For a simple two-user chat, WebSockets are fine; as the requirements grow, MQTT becomes attractive.
Live sports scores or news feeds pushed to a website. SSE. One-way, no messaging complexity, native browser support. MQTT is technically better on almost every axis but the operational simplicity of SSE (no broker, no MQTT library in the browser) wins for this shape of use case.
Multiplayer game state synchronization. WebSockets, in most cases. Games often need very low latency and custom binary protocols; MQTT’s abstractions are useful but not always worth the tradeoff. That said, some large multi-player IoT-adjacent games (drone racing, connected vehicles as “players”) use MQTT for the persistent-connection and fan-out advantages.
Dashboard receiving updates from many devices. MQTT. Each device publishes to its own topic; the dashboard subscribes to a wildcard. Adding more devices adds no work on the dashboard side. Doing the same with HTTP-based approaches requires either a lot of per-device work or a message-fan-out layer that is essentially a broker.
Command and control of a small number of connected devices. Either MQTT or WebSockets works. If the devices are constrained or intermittently connected, MQTT is the safer choice; if the devices are always online, well-resourced, and you already have HTTP/WebSocket infrastructure, WebSockets are simpler to add.
Web app receiving push notifications from a backend. SSE for one-way, WebSockets if the client also needs to send. MQTT works but running a broker just for browser notifications is usually overkill.
Industrial sensor network with unreliable cellular connectivity. MQTT. QoS, persistent sessions, keep-alive, and Last Will and Testament are what you need on these networks. HTTP-based approaches simply do not have equivalent built-in mechanisms.
The connection model is where MQTT quietly wins
One thing worth calling out separately, because it is often invisible until you hit it: the connection model of MQTT is designed to be sustained cheaply on both ends, and the connection model of HTTP is not, even when HTTP is being used for persistent connections.
An MQTT connection is meant to stay open for hours, days, or the lifetime of the device. The keep-alive is a two-byte packet exchanged only when nothing else is flowing. The broker knows how to detect half-open connections (see the Keep Alive article) and how to store queued messages while a client is offline (see Persistent Sessions). Reconnection resumes state cleanly.
An HTTP connection, even a long-lived one used for SSE or WebSockets, was not designed with this in mind. Load balancers time out idle connections at 30 or 60 seconds by default. Reverse proxies impose their own limits. A device that sleeps between messages has to work harder to keep the connection technically alive through all the intermediate infrastructure, and if it fails, the reconnect is a full HTTP handshake plus TLS plus WebSocket upgrade plus application-level state re-establishment. MQTT reconnection is faster and, with a persistent session, resumes from where it left off automatically.
For a small deployment this rarely matters. For a fleet of ten thousand devices reconnecting through a load-balanced infrastructure over unreliable cellular, the difference between MQTT’s connection model and an HTTP-based equivalent is a real one that shows up in cost, in complexity, and in operational fragility. This is one of the reasons “just use WebSockets” is often the right answer for a web application and the wrong answer for an IoT fleet.
Can you use both?
Yes, and this is a very common architecture. Many production systems use MQTT for device-to-backend messaging and HTTP for backend-to-frontend APIs and web services. Devices connect to an MQTT broker; the broker forwards messages into backend systems; web clients query those backend systems over HTTP. The two protocols coexist because they solve different parts of the problem.
Some deployments also expose MQTT over WebSockets so browser-based dashboards can subscribe to MQTT topics directly (see the MQTT Over WebSockets article), which unifies the messaging layer while keeping HTTP available for everything else. This is a genuinely powerful architecture: the backend and devices communicate over efficient plain MQTT; the browser gets MQTT semantics over WebSockets; the web application uses HTTP for the rest.
Choosing between HTTP and MQTT is not a binary decision for the whole system. It is a per-communication-pattern decision, and the right answer for each pattern gives you a coherent architecture.
Frequently asked questions
Is MQTT better than HTTP? For real-time messaging, especially IoT-style patterns with many devices, small payloads, and bidirectional flow, yes — MQTT is designed for exactly that and does it more efficiently than HTTP. For request/response APIs, static content, and one-off data fetches, HTTP is the better fit. Neither is universally better.
Can MQTT replace HTTP? No, and it is not meant to. MQTT is a messaging protocol; HTTP is a web protocol. They coexist in most real systems.
Is MQTT faster than HTTP? MQTT has lower per-message overhead than HTTP, which usually makes it feel “faster” for small, frequent messages. For a single large request/response, HTTP is not slower in any meaningful way. The difference matters most when messages are small and frequent.
Can I run MQTT in a browser? Yes, via MQTT over WebSockets. Browsers cannot open raw TCP connections, so plain MQTT is not usable there, but MQTT-over-WebSockets libraries exist for JavaScript and give the browser a full MQTT client.
Is WebSockets a good alternative to MQTT? WebSockets are a lower-level transport. They give you a bidirectional binary channel and nothing else. MQTT sits on top of a TCP connection (or a WebSocket) and adds pub/sub, delivery guarantees, retained messages, sessions, LWT. If you need those features, MQTT is the answer; if you do not, WebSockets are simpler.
When should I use SSE instead of MQTT? When the messaging is one-way (server to client), the client does not need MQTT’s delivery guarantees, and you want to avoid running an MQTT broker. SSE is native to browsers and cheaper to operate than MQTT for this specific shape of use case.
Which uses more bandwidth, HTTP or MQTT? HTTP, almost always, especially for small frequent messages. HTTP header overhead per message is much larger than MQTT’s two-byte fixed header. Over TLS the difference narrows but does not disappear.
Does MQTT work over HTTP? Not directly, but MQTT over WebSockets rides on the same TCP ports as HTTPS (443) and behaves like an HTTPS connection from a network’s perspective, which is close enough for firewall traversal. See the MQTT Over WebSockets article for details.
Can I use HTTP for IoT? You can, and many small deployments do. But for anything with many devices, unreliable connections, small payloads, or bidirectional command flow, MQTT is a significantly better fit and will save you real work over time.
