Technology

MQTT vs HTTP for IoT, or SMS: how should a station report?

What a broker, a topic and a QoS level actually do, what each protocol costs in bytes and battery, and which one to use when the mobile signal comes and goes.

A solar-powered river station takes a reading every 15 minutes, in a valley where the mobile signal comes and goes, and is often gone during the storm that matters. The reading has to reach a server, and now and then the server has to reach the station: a new reporting interval, a clock correction, a siren to sound. The question engineers then ask is MQTT vs HTTP for IoT devices like this one, and where SMS fits.

The short answer: how a protocol is used matters more than which one. This article explains each option from its standard, then compares them on bytes, delivery, outages, commands and power.

Three diagrams. MQTT: a field station publishes to a broker, which passes readings to a database and passes commands from a control centre back to the station. HTTP: the station sends a request to a web server and gets a response. SMS: the station sends a message through the operator's Service Centre to an SMS gateway, and commands come back the same way.
The three ways a field station can report. With MQTT the station keeps one connection to a broker and data flow both ways on it. With HTTP the station asks and the server answers. With SMS the operator's Service Centre stores and forwards each short message. Credit: original, ClimMaTech

What is an MQTT broker, and how does MQTT work?

An MQTT broker is the server that every device and application connects to; it receives each message and passes it on to whoever has asked for it. MQTT itself is defined by OASIS as "a Client Server publish/subscribe messaging transport protocol", designed to be "light weight, open, simple" for machine-to-machine and Internet of Things uses "where a small code footprint is required and/or network bandwidth is at a premium" [1]. Two versions are published OASIS Standards: MQTT 3.1.1 (2014) [2] and MQTT 5.0 (2019) [1], which adds features such as message expiry and reason codes.

The vocabulary:

  • Client: anything that connects to the broker: the station, the database, the control-centre software.
  • Topic: a text label on each message, such as stn/042/wl for station 42's water level.
  • Publish and subscribe: a client publishes a message to a topic; any client that has subscribed to that topic receives a copy. Neither side needs to know the other's address.
  • Connection: MQTT runs over TCP/IP, or another network protocol "that provide[s] ordered, lossless, bi-directional connections" [1]. The station opens it; both directions use it. The registered ports are 1883 for plain MQTT and 8883 for MQTT over TLS, the encryption layer that also secures HTTPS [1].

HTTP, by contrast, is "a stateless request/response protocol" [3]: the station asks and the server answers. Under MQTT the broker can push a message to the station whenever the connection is open.

MQTT QoS explained: 0, 1 and 2

Quality of service (QoS) is the delivery promise attached to each message. MQTT 5.0 defines three levels [1]:

QoSNameWhat happensWhat the standard says
0At most onceSent once, never confirmed"Message loss can occur"; suits "ambient sensor data where it does not matter if an individual reading is lost"
1At least onceThe receiver answers with a PUBACK; the sender keeps the message until then and, if the connection breaks, resends it after reconnectingMessages "are assured to arrive but duplicates can occur"
2Exactly onceA four-packet exchangeFor when "neither loss nor duplication of messages are acceptable"; "an increased overhead"

For a flood station, QoS 1 is the sensible choice. A lost reading as the river crosses its danger level is worse than a duplicate, and duplicates are easy to remove on the server because each reading carries its station number and time. QoS 2 costs two extra packets per message on exactly the links where every round trip is slow. The promise covers one hop at a time: station to broker, then broker to each subscriber, at no more than the maximum QoS that subscriber asked for [1].

Retained messages, keep-alive and last will

Retained messages. If a client publishes with the RETAIN flag set, the broker stores that message and replaces any earlier one on the same topic [1]. New subscribers receive it at once; the standard notes that this is useful "where publishers send state messages on an irregular basis" [1]. A station's configuration or online/offline status fits; a siren trigger does not, because a retained "sound the siren" would reach every later subscriber.

Keep-alive. In its CONNECT packet the client states a keep-alive time in seconds. If it has nothing else to send within that time, it must send a PINGREQ, and the broker replies with PINGRESP; each is just a 2-byte fixed header [1]. If the broker hears nothing from the client "within one and a half times the Keep Alive time period", it must close the connection "as if the network had failed" [1]. The standard calls the value application specific: "typically, this is a few minutes", up to a maximum of 65,535 s, just over 18 hours [1].

Last will. When it connects, a station can leave a will message with the broker, for example offline on topic stn/042/status. The broker publishes it if the connection closes without a normal DISCONNECT: after a network failure, or when the client misses its keep-alive [1]. The control centre learns within minutes that a station has gone silent.

Sessions. A client can ask the broker to keep its session after a disconnection, by connecting with Clean Start set to 0 and a Session Expiry Interval greater than zero [1]. The session holds the client's subscriptions and any QoS 1 and QoS 2 messages waiting to be delivered to it [1]. This is how a command reaches a station that was offline when the command was sent.

Sequence diagram between a field station, a broker and subscribers. The station connects with a 300 s keep-alive and a will, publishes a retained online status, publishes a reading at QoS 1 and receives a PUBACK, and sends a PINGREQ when it has nothing to send. The mobile link drops; the station keeps storing readings; after 450 s without traffic the broker closes the connection and publishes the will, status offline. A command sent at QoS 1 is held in the station's session. When the link returns, the station reconnects, receives the queued command and sends its status and stored readings.
An MQTT session through an outage, with an illustrative 300 s keep-alive. The broker declares the station lost after 1.5 times the keep-alive and publishes its will. A QoS 1 command waits in the station's session, which must have been opened with Clean Start 0 and a non-zero Session Expiry Interval, and is delivered on reconnection. Credit: original, ClimMaTech

SMS: 160 characters through a store-and-forward centre

SMS (Short Message Service) needs no internet connection, only registration on the mobile network. The operator's Service Centre "acts as a store and forward centre for short messages" [11], so a message to a station that is out of reach is held and retried rather than lost at once, although the sender can set a validity period after which the centre gives up [11].

Each message carries "up to 140 octets" [11]. In the GSM 7-bit default alphabet, which every phone and Service Centre must support, that is "up to 160 characters" [10], because (140 × 8) / 7 = 160 [10]. Some characters, including { } [ ] ~, come from an extension table and use two places each [10], so JSON braces are expensive. Binary (8-bit) data also gets 140 octets; Unicode text (UCS2) gets only 70 characters [10]. Longer messages are split into concatenated segments, each carrying a header that leaves 153 characters, or 134 octets of binary data [11].

The sender can request a status report from the Service Centre [11], but each message is charged separately, so SMS is best for a few short, important messages: an alarm, a daily summary, a command when the data link is down.

How many bytes does one reading cost?

This is an illustrative worked example: the payload, topic, credentials and TLS handshake sizes are assumptions chosen to show the arithmetic. The reading is a 52-byte JSON message:

{"id":"STN042","t":1766720700,"wl":2.437,"bv":12.61}      52 bytes

The layers each message passes through add their own bytes:

IPv4 header                     20 bytes minimum [14]
TCP header                      20 bytes minimum [5]
TLS 1.3 record                  5-byte header + 1 content-type byte [6]
                                + 16-byte AES-GCM tag [7]   = 22 bytes
Opening a TCP connection        3 packets (SYN, SYN-ACK, ACK) [5] = 120 bytes
Closing it                      4 packets (FIN, ACK, FIN, ACK)   = 160 bytes
Full TLS 1.3 handshake          assume 5,000 bytes in total, most of it
                                the server's certificate chain
Resumed TLS 1.3 handshake       assume 800 bytes (no certificate is sent
                                when a pre-shared key is reused [6])

HTTPS, new connection for each reading. An HTTP/1.1 request is a start line, header fields and a blank line, followed by the content [4]:

POST /v1/readings HTTP/1.1
Host: data.example.in
Authorization: Bearer 3f9a1c7e5b2d4a6f8e0c1b3d5f7a9e2c
Content-Type: application/json
Content-Length: 52
                                                header: 161 bytes
Request:  161 + 52 + 22 (TLS) + 40 (IP/TCP)   =   275 bytes
Response: "HTTP/1.1 204 No Content" + Date = 64 + 22 + 40 = 126 bytes
Total:    120 + 5,000 + 275 + 126 + 160        = 5,681 bytes

MQTT, connection kept open. A QoS 1 PUBLISH has a 1-byte packet type, a 1-byte length, the topic with a 2-byte length prefix, a 2-byte packet identifier and a 1-byte property length [1]; the PUBACK is 4 bytes [1]:

PUBLISH:  1 + 1 + (2 + 10) + 2 + 1 + 52      =  69 bytes
          + 22 (TLS) + 40 (IP/TCP)           = 131 bytes
PUBACK:   4 + 22 + 40                        =  66 bytes
Per reading                                  = 197 bytes
With a 300 s keep-alive, two ping exchanges fit between 15-minute
readings:  2 × 2 × (2 + 22 + 40)             = 256 bytes
Per reading, including keep-alive            = 453 bytes

MQTT, reconnecting for each reading. The station also sends a CONNECT (here 60 bytes with a short client name, user name and password, and no will) and a 2-byte DISCONNECT, and receives a 5-byte CONNACK [1]. With a full TLS handshake each time, the total is 5,730 bytes, slightly more than HTTPS.

Bytes on the air for one 52-byte reading (illustrative)
02,5005,0007,50010,000Payload aloneMQTT kept openMQTT kept ope…HTTPS with re…MQTT reconnec…HTTPS new con…MQTT reconnec…bytes
Computed in the worked example from the header sizes in the MQTT, HTTP, TCP, IP and TLS standards, an assumed 5,000-byte full and 800-byte resumed TLS handshake, and a 15-minute reporting interval. Bare TCP acknowledgements, TLS closing messages and retransmissions are left out.

Three lessons follow. Opening a secure connection costs about a hundred times the reading. The connection pattern matters more than the protocol: MQTT that reconnects for every reading costs as much as HTTPS. And keep-alive is not free: here the pings cost more than the reading. At 2,880 readings a month, the open MQTT connection uses about 1.3 MB, HTTPS with a new full handshake each time about 16 MB.

An SMS of the same reading, written as plain text (STN042 1766720700 2.437 12.61, 29 characters), fits in one 160-character message, but the cost is counted per message, not per byte.

No protocol keeps a reading safe on its own. That is the job of store and forward in the station: every reading goes to non-volatile memory first and is marked as sent only when the server confirms it. The confirmation differs:

  • MQTT QoS 1: the PUBACK. When a client reconnects to a kept session (Clean Start 0, session present), client and server "MUST resend any unacknowledged PUBLISH packets" [1]. If the station starts a new session each time, its own store and forward must do the resending.
  • HTTP: the status code. POST is not idempotent (repeating it may not have the same effect as sending it once), and the standard says a client "SHOULD NOT automatically retry a request with a non-idempotent method" unless it knows the request is safe to repeat [3]. Make the server accept repeats, for example by keying each reading on station and time, or use PUT, which is idempotent [3].
  • SMS: a status report, if one was requested; otherwise nothing comes back to the station.

After an outage the station sends its backlog, ideally in batches that spread the connection cost, newest reading first for a warning station. Payload formats and backfill are covered in from sensor to screen.

Two-way commands: configuration and siren triggers

A network also sends things to its stations: a new reporting interval, a clock correction, or a siren command once an authorised operator has approved the alert in the control centre.

  • MQTT: the station subscribes to its own command topic, such as stn/042/cmd, and receives commands at once while connected. With a kept session, QoS 1 commands sent while it was offline are delivered when it reconnects [1]. For time-critical commands, MQTT 5.0's Message Expiry Interval lets the broker delete a message that could not be delivered in time [1], so that a siren command from yesterday's storm is not obeyed tomorrow. Never retain an action command, and have the station publish an acknowledgement so the control centre knows the command was carried out.
  • HTTP: the station collects pending commands with each upload, so the delay is up to one reporting interval.
  • SMS: a command can reach a station whose data connection is down, a useful second path for sirens. A phone number is not proof of identity, so act only on SMS commands that carry an authentication code.

For more on how warnings reach people, see early warning dissemination: sirens, SMS and CAP.

Power: an open line or a quick call

The radio is "typically the most power-consuming component", and a radio waiting to receive "may consume as much power in listen mode as when actively transmitting"; the remedy is to switch it off as much as possible [13]. That is the core trade-off:

  • Persistent connection (MQTT kept open): commands arrive at once and each reading is cheap, but the modem must stay connected and answer keep-alives around the clock.
  • Wake, send, sleep: the station connects, sends a batch, collects commands and switches its modem off. It pays the connection cost each time (so batch readings and reuse TLS sessions), but the radio is off most of the hour. RFC 8352 notes that devices that "sleep for very long periods and communicate infrequently" save the most, "even though they spend energy in network reattachment procedures" [13].

Cellular networks offer a middle way. In LTE Power Saving Mode (PSM), a device stays registered with the network but "is not immediately reachable for mobile terminating services"; it can be reached while connected and for an "Active Time" afterwards, and an SMS or device trigger sent meanwhile is delivered when it next becomes reachable [12]. Commands wait for the next wake-up: acceptable for configuration, not for a siren.

For sizing panel and battery, see sizing solar power for an off-grid monitoring station.

MQTT vs CoAP

The Constrained Application Protocol (CoAP) is an IETF protocol "for use with constrained nodes and constrained (e.g., low-power, lossy) networks" [8]. It keeps HTTP's request/response model and is "designed to easily interface with HTTP", but runs over UDP with a fixed 4-byte header [8], so there is no TCP connection to open. Reliability is optional: a Confirmable message is resent with exponential back-off until acknowledged (by default first after 2 to 3 s, up to 4 times), while a Non-confirmable message is sent once [8]. Security comes from DTLS, the datagram version of TLS [8], and the Observe extension lets a client follow a resource as it changes [9].

In short, CoAP is low-overhead request/response without a connection; MQTT is publish/subscribe through a broker over a connection. CoAP suits platforms built around UDP; MQTT fits better when many stations report to one centre that must push commands.

Which should you use?

SituationSuggested approach
Warning station on solar power with usable GSM/4G, sirens or commands neededMQTT over TLS, connection kept open, QoS 1, a few minutes' keep-alive, last will, kept session; store and forward in the station
Battery-only station reporting every hour or less often, no urgent commandsWake, connect, send a batch (MQTT QoS 1 or HTTPS), collect commands, sleep; reuse TLS sessions
Data must go straight into an existing web APIHTTPS with requests that are safe to repeat (PUT, or POST keyed on station and time); batch the backlog
Patchy data coverage, signal good enough for SMSMain channel as above, plus SMS for threshold alarms and a daily summary
No data service at allSMS only: compact plain-text readings, a sequence number in each message, low reporting rate
Platform built around UDP and constrained devicesCoAP with Confirmable messages for readings that must arrive

Whatever the channel, the rules are the same: store every reading before sending it, mark it sent only on confirmation, remove duplicates on the server, and let the station report its own health. The radio link beneath all of this is covered in telemetry link design.

Key points

  • MQTT: publish/subscribe through a broker, both ways over one connection. HTTP: request/response started by the station. SMS: store and forward through the operator, 160 GSM 7-bit characters.
  • Use QoS 1 for readings that matter and remove duplicates on the server.
  • Retained messages suit configuration and status, never action commands. Keep-alive and last will tell the control centre when a station falls silent.
  • In our example, opening a secure connection cost about a hundred times the reading. Keep the connection open, or batch readings and reuse TLS sessions.
  • Store and forward in the station, not the protocol, protects data through an outage.
  • Commands reach an open MQTT connection at once; HTTP and sleeping devices wait; SMS is a useful second path.

Where ClimMaTech fits

Our monitoring devices log every reading on board and keep the record when the network is down, and every one has GSM to report to Visiflow (Device Cloud), which shows every station with live readings, history and alerts. Where an organisation needs the data in its own system, our devices support MQTT and open APIs, as described on our RTDAS and hydromet telemetry page. We are glad to talk through the reporting design for your stations and their network conditions.

References

  1. OASIS, MQTT Version 5.0, OASIS Standard, 7 March 2019. Sections 1, 3.1.2 (Clean Start, Will Flag, Keep Alive), 3.1.3, 3.3 (PUBLISH, RETAIN, Message Expiry Interval), 3.4, 3.12, 4.1, 4.3, 4.4, 4.8, 5.1. docs.oasis-open.org.
  2. OASIS, MQTT Version 3.1.1, OASIS Standard, 29 October 2014. docs.oasis-open.org.
  3. Fielding, R., Nottingham, M. and Reschke, J. (eds.), HTTP Semantics, RFC 9110, IETF, 2022. Sections 3.4 and 9.2.2. rfc-editor.org.
  4. Fielding, R., Nottingham, M. and Reschke, J. (eds.), HTTP/1.1, RFC 9112, IETF, 2022. rfc-editor.org.
  5. Eddy, W. (ed.), Transmission Control Protocol (TCP), RFC 9293, IETF, 2022. Sections 3.1 and 3.5. rfc-editor.org.
  6. Rescorla, E., The Transport Layer Security (TLS) Protocol Version 1.3, RFC 8446, IETF, 2018. Sections 2, 2.2, 4.4.2 and 5.2. rfc-editor.org.
  7. McGrew, D., An Interface and Algorithms for Authenticated Encryption, RFC 5116, IETF, 2008. Section 5.1. rfc-editor.org.
  8. Shelby, Z., Hartke, K. and Bormann, C., The Constrained Application Protocol (CoAP), RFC 7252, IETF, 2014. rfc-editor.org.
  9. Hartke, K., Observing Resources in the Constrained Application Protocol (CoAP), RFC 7641, IETF, 2015. rfc-editor.org.
  10. 3GPP, Alphabets and language-specific information, TS 23.038 version 19.0.0 (ETSI TS 123 038 V19.0.0), ETSI, 2025. Clauses 4, 6.1.2.1.1 and 6.2.1.1. etsi.org PDF.
  11. 3GPP, Technical realization of the Short Message Service (SMS), TS 23.040 version 19.0.0 (ETSI TS 123 040 V19.0.0), ETSI, 2025. Introduction, clauses 3.1, 9.2.3.5, 9.2.3.12 and 9.2.3.24.1. etsi.org PDF.
  12. 3GPP, Architecture enhancements to facilitate communications with packet data networks and applications, TS 23.682 version 18.0.0 (ETSI TS 123 682 V18.0.0), ETSI, 2024. Clause 4.5.4. etsi.org PDF.
  13. Gomez, C., Kovatsch, M., Tian, H. and Cao, Z. (eds.), Energy-Efficient Features of Internet of Things Protocols, RFC 8352, IETF, 2018. Sections 3 and 7. rfc-editor.org.
  14. Postel, J. (ed.), Internet Protocol, RFC 791, IETF, 1981. Section 3.1. rfc-editor.org.
mqtthttpsmscoaptelemetryiotstore and forwardhydromet
Shivam kumar
Written by
SDE