MQTT vs HTTP: How to Choose the Right IoT Communication Protocol?
IoT devices need to communicate with the cloud, and choosing the right communication protocol directly impacts system performance, battery life, and maintenance costs. This article provides an in-depth comparison of MQTT and HTTP, the two mainstream protocols, to help you make the best choice.
Protocol Overview
HTTP (HyperText Transfer Protocol)
HTTP is the foundational protocol of the Web, using a request-response model:
Client ──Request──> Server
Client <──Response── Server
Characteristics:
- Stateless protocol
- Request-response model
- Text-based headers (HTTP/1.1)
- Broad support and mature toolchain
MQTT (Message Queuing Telemetry Transport)
MQTT is a lightweight publish-subscribe protocol designed specifically for IoT:
Publisher ──Publish Message──> Broker ──Push──> Subscriber
Characteristics:
- Publish/Subscribe model
- Minimal packet overhead
- Persistent connections
- QoS (Quality of Service) guarantees
Performance Comparison
Bandwidth Consumption
| Item | MQTT | HTTP |
|---|---|---|
| Header Size | 2-5 bytes | 700+ bytes |
| Connection Establishment | Once | Per request |
| Keep-alive | Minimal | N/A |
For scenarios involving frequent transmission of small data packets, MQTT's bandwidth advantage is significant:
// MQTT sending sensor data (ESP32)
void send_mqtt_data(float temperature, float humidity) {
char payload[64];
snprintf(payload, sizeof(payload),
"{\"temp\":%.1f,\"hum\":%.1f}", temperature, humidity);
// Actual transmission: 2 bytes fixed header + topic length + payload
// Total approximately 30-50 bytes
mqtt_client_publish(client, "sensors/living-room", payload, 0, 0);
}
// HTTP sending the same data
void send_http_data(float temperature, float humidity) {
char body[64];
snprintf(body, sizeof(body),
"{\"temp\":%.1f,\"hum\":%.1f}", temperature, humidity);
// HTTP request includes:
// - Request line: POST /api/sensors HTTP/1.1
// - Host, Content-Type, Content-Length and other headers
// - Empty line + body
// Total approximately 300-500 bytes
http_client_post(client, "/api/sensors", body);
}
Latency Comparison
MQTT's persistent connections significantly reduce latency:
| Scenario | MQTT | HTTP |
|---|---|---|
| Initial Connection | ~100ms | ~100ms |
| Subsequent Messages | ~10ms | ~100ms |
| Server Push | Real-time | Requires polling |
Power Consumption
For battery-powered devices, MQTT is more power-efficient:
HTTP per-request flow:
1. TCP handshake (3 round trips)
2. TLS handshake (2-4 round trips)
3. HTTP request/response
4. Connection close
MQTT persistent connection:
1. Initial connection establishment (same as HTTP)
2. Subsequent messages only require small packets
3. Keep-alive maintains the connection
Measured data (ESP32 + WiFi):
| Operation | MQTT | HTTP |
|---|---|---|
| Send one data point | 15 mAs | 80 mAs |
| Send once per minute | 900 mAs/hr | 4800 mAs/hr |
Feature Comparison
Quality of Service (QoS)
MQTT provides three QoS levels:
// QoS 0: At most once (Fire and Forget)
// No delivery guarantee, lowest overhead
mqtt_publish(client, topic, payload, QOS_0, false);
// QoS 1: At least once
// Guaranteed delivery, may duplicate
mqtt_publish(client, topic, payload, QOS_1, false);
// QoS 2: Exactly once
// Guaranteed delivery without duplicates, highest overhead
mqtt_publish(client, topic, payload, QOS_2, false);
HTTP requires implementing retry mechanisms at the application layer.
Server Push
MQTT natively supports server push:
// Subscribe to a topic, automatically receive new messages
void mqtt_message_handler(char *topic, char *payload) {
if (strcmp(topic, "commands/device-001") == 0) {
handle_command(payload);
}
}
mqtt_subscribe(client, "commands/device-001", QOS_1, mqtt_message_handler);
HTTP requires one of the following approaches:
- Polling: Periodic requests, wastes bandwidth
- Long Polling: Occupies connections
- WebSocket: Additional complexity
Offline Messages
MQTT supports offline message caching:
// Set Clean Session = false, Broker will retain offline messages
mqtt_connect_options opts = {
.client_id = "device-001",
.clean_session = false, // Retain session state
};
// Using Retained Message, new subscribers receive the last message
mqtt_publish(client, "status/device-001", "online", QOS_1, true);
Implementation Examples
ESP32 MQTT Client
#include "mqtt_client.h"
static esp_mqtt_client_handle_t mqtt_client;
// MQTT event handler
static void mqtt_event_handler(void *args, esp_event_base_t base,
int32_t event_id, void *event_data) {
esp_mqtt_event_handle_t event = event_data;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT connected");
// Subscribe to command topic
esp_mqtt_client_subscribe(mqtt_client, "commands/#", 1);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "Message received: %.*s", event->data_len, event->data);
process_message(event->topic, event->data);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "MQTT disconnected, auto-reconnecting...");
break;
}
}
void mqtt_init(void) {
esp_mqtt_client_config_t config = {
.broker.address.uri = "mqtts://broker.example.com",
.credentials.client_id = "esp32-device-001",
.session.keepalive = 60,
};
mqtt_client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID,
mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
}
// Publish sensor data
void publish_sensor_data(float temp, float humidity) {
char payload[128];
snprintf(payload, sizeof(payload),
"{\"temperature\":%.2f,\"humidity\":%.2f,\"timestamp\":%lld}",
temp, humidity, esp_timer_get_time() / 1000);
esp_mqtt_client_publish(mqtt_client, "sensors/esp32-001",
payload, 0, 1, 0);
}
Node.js MQTT Broker Side
const mqtt = require('mqtt');
const client = mqtt.connect('mqtt://broker.example.com');
// Subscribe to all sensor data
client.on('connect', () => {
client.subscribe('sensors/#', (err) => {
if (!err) console.log('Subscribed to sensors topic');
});
});
// Handle received messages
client.on('message', (topic, message) => {
const data = JSON.parse(message.toString());
console.log(`[${topic}] Temperature: ${data.temperature}°C`);
// Save to database
saveToDatabase(topic, data);
// Check if alert is needed
if (data.temperature > 30) {
client.publish('alerts/high-temp', JSON.stringify({
device: topic.split('/')[1],
temperature: data.temperature,
}));
}
});
Selection Recommendations
When to Choose MQTT
- Frequent small data transmissions: Sensors reporting every second or minute
- Battery-powered devices: Need to minimize wireless transmission
- Real-time push required: Remote control, alert notifications
- Unstable networks: QoS guarantees message delivery
- Large device fleets: Tens of thousands of devices connected simultaneously
When to Choose HTTP
- Infrequent data uploads: Reporting a few times per day
- Large data transfers: Firmware updates, log uploads
- Web service integration: Using existing REST APIs
- Simple implementation: No need to deploy an additional Broker
- Firewall restrictions: Only ports 80/443 are open
Hybrid Architecture
Many systems use both protocols simultaneously:
┌─────────────────────────────────────────────────────┐
│ Cloud Services │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ MQTT Broker │ │ REST API │ │
│ │ (Real-time │ │ (Query/ │ │
│ │ data) │ │ Config) │ │
│ └──────┬──────┘ └──────┬──────┘ │
└─────────┼───────────────────────┼───────────────────┘
│ │
MQTT │ HTTP │
▼ ▼
┌─────────────────────────────────────────────────────┐
│ IoT Devices │
│ - Real-time sensor data → MQTT │
│ - Firmware updates → HTTP │
│ - Configuration changes → HTTP │
└─────────────────────────────────────────────────────┘
Conclusion
Both MQTT and HTTP have their strengths. When choosing, consider:
| Consideration | MQTT is Better | HTTP is Better |
|---|---|---|
| Transmission Frequency | High frequency | Low frequency |
| Data Size | Small payloads | Large payloads |
| Real-time Requirements | Required | Not required |
| Power Budget | Constrained | Sufficient |
| Infrastructure | Can deploy Broker | Use existing services |
If you are planning an IoT project, feel free to contact us to discuss the most suitable communication architecture.