
September 11, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
MQTT for IoT messaging solves a problem HTTP was never designed for: thousands of tiny devices sending short updates over flaky mobile or Wi-Fi links while running on battery. Sensors, gateways, and dashboards need a protocol that keeps payloads small, reconnects quietly, and does not require the device to poll a server every few seconds. If you build connected products, fleet trackers, or smart-building dashboards, you will eventually evaluate MQTT alongside the lightweight messaging patterns you already use in web backends. This guide covers how MQTT works, how to run a broker safely, and how it connects to the PHP and Laravel stacks many teams already maintain.
What is MQTT and why is it the default for IoT messaging?
MQTT stands for Message Queuing Telemetry Transport. Despite the name, it is not a traditional message queue. It is a pub/sub wire protocol designed in 1999 for oil-pipeline telemetry and standardised by OASIS MQTT v5.0. Version 5 adds session expiry, user properties, and shared subscriptions; most production fleets still run MQTT 3.1.1 because every embedded SDK supports it.
The protocol fits IoT because a single PUBLISH frame can carry a few bytes of sensor data. A typical JSON reading over HTTPS needs headers, TLS, and a full HTTP round trip. MQTT keeps the connection open and sends only what changed. On a 2G link in rural Nepal or a congested factory floor, that difference shows up in billable data and device uptime.
Three roles define every deployment:
- Publisher — a device or service that sends messages to a topic.
- Subscriber — any client that receives messages matching a topic filter.
- Broker — the server that accepts connections, enforces ACLs, and routes messages.
Devices never talk to each other directly. They talk to the broker. That indirection is what makes MQTT scale: add ten thousand sensors without reconfiguring your dashboard.
Where MQTT shows up in real products
MQTT appears in smart agriculture soil probes, cold-chain temperature loggers, parking occupancy sensors, and industrial PLCs bridged to cloud dashboards. On booking and logistics platforms I have worked on, GPS trackers and SMS gateways often expose MQTT as one ingestion path while the web app still runs on Laravel and MySQL. The protocol layer stays separate from the business logic layer, which is exactly how you want it.
How does the MQTT publish-subscribe model work?
Every message belongs to a topic, a UTF-8 string with slash-separated levels. A temperature reading from warehouse three might publish to site/kathmandu/wh3/temp. Subscribers use filters:
site/kathmandu/wh3/temp— exact match.site/kathmandu/+/temp— single-level wildcard.site/#— multi-level wildcard.
Design topics for operations, not for individual device serial numbers alone. A pattern like org/{orgId}/device/{deviceId}/telemetry keeps ACL rules readable and makes it easy to subscribe to all devices in one org.
Quality of Service levels
MQTT defines three QoS levels. Pick the lowest level that meets your reliability requirement; higher QoS costs bandwidth and broker storage.
| QoS | Name | Delivery guarantee | Typical IoT use |
|---|---|---|---|
| 0 | At most once | Fire and forget; may lose messages | High-frequency telemetry where the next reading replaces the last |
| 1 | At least once | Acknowledged; duplicates possible | Alerts, door events, billing triggers |
| 2 | Exactly once | Four-part handshake; no duplicates | Financial or safety-critical commands |
Most sensor streams use QoS 0 or 1. I have seen teams default everything to QoS 2 and then wonder why broker CPU spikes. Match QoS to business impact, not to maximum safety reflex.
Retained messages and Last Will
A retained message stores the last payload on a topic so new subscribers get the current state immediately. Use it for device online status or last-known configuration, not for high-frequency streams.
Last Will and Testament (LWT) tells the broker to publish a message if the client disconnects unexpectedly. A common pattern publishes to devices/{id}/status with payload offline when a sensor drops off the network without a clean DISCONNECT.
Keep-alive and clean sessions
Clients send PINGREQ frames within the keep-alive interval to prove they are alive. Set keep-alive based on network behaviour: 30–60 seconds on stable Wi-Fi, longer on NB-IoT if your broker allows it. With MQTT 5, session expiry replaces the older clean-session flag and gives you explicit control over offline message buffering.
How do you set up an MQTT broker for production IoT workloads?
The broker is infrastructure, not application code. Treat it like you treat Redis or MySQL: hardened host, TLS, monitoring, and backups of configuration at minimum.
Broker options compared
| Broker | Best for | Clustering | Notes |
|---|---|---|---|
| Eclipse Mosquitto | Single-node, edge, dev/staging | Limited bridge mode | Lightweight, widely packaged on Ubuntu |
| EMQX | High-connection cloud deployments | Native clustering | Built-in rule engine and HTTP webhook bridge |
| HiveMQ | Enterprise SLA requirements | Yes | Commercial support and extensions |
| AWS IoT Core | AWS-native fleets | Managed | Per-message pricing; tight IAM integration |
For a first production deployment on a VPS you manage yourself, Mosquitto on Ubuntu 24 with TLS from Let's Encrypt is a sane starting point. Move to EMQX or a managed service when connection counts exceed what one node handles comfortably. Linux server administration for broker hardening follows the same patterns as any other public-facing daemon: non-root service user, UFW, fail2ban, and log rotation.
Install Mosquitto with TLS on Ubuntu
# Install broker and clients
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
# Create password file
sudo mosquitto_passwd -c /etc/mosquitto/passwd device_001
# /etc/mosquitto/conf.d/production.conf
listener 8883
certfile /etc/letsencrypt/live/mqtt.example.com/fullchain.pem
keyfile /etc/letsencrypt/live/mqtt.example.com/privkey.pem
require_certificate false
allow_anonymous false
password_file /etc/mosquitto/passwd
# ACL file — devices publish only to their own branch
# /etc/mosquitto/acl
user device_001
topic write site/kathmandu/device_001/#
topic read site/kathmandu/device_001/config
sudo systemctl restart mosquitto Test from your laptop before you flash firmware:
mosquitto_pub -h mqtt.example.com -p 8883 \
--cafile /path/to/ca.crt -u device_001 -P 'secret' \
-t 'site/kathmandu/device_001/telemetry' \
-m '{"temp":24.1,"hum":62}' -q 1 Validate inbound JSON with a JSON formatter and linter during development so malformed payloads never reach your database writers.
Operational checklist
- Enable TLS on port 8883; block plain 1883 from the public internet.
- Issue unique credentials or client certificates per device batch.
- Define ACL files so a compromised sensor cannot publish to foreign topics.
- Set connection limits and message size caps in broker config.
- Ship logs to your existing stack; pair with Prometheus-style alerting on connection count and publish rate.
- Document topic naming in your internal wiki before firmware teams diverge.
Reference the Eclipse Mosquitto documentation for directive names; they change little between releases but defaults are not production-safe out of the box.
When should you choose MQTT over HTTP or WebSockets for IoT?
HTTP works when devices send data rarely and already speak REST. MQTT wins when connections stay open, payloads stay under a kilobyte, and you publish more often than once per minute per device.
| Criteria | MQTT | HTTPS REST | WebSockets |
|---|---|---|---|
| Payload overhead | 2-byte header minimum | Full HTTP headers each request | Low after upgrade |
| Push to device | Native via subscribed topics | Requires polling or separate channel | Native bidirectional |
| Offline buffering | Broker queues for clean sessions | Client must retry POST | App must implement queue |
| Firewall traversal | Often blocked except 8883 | Port 443 usually open | Same as HTTP upgrade |
| PHP/Laravel fit | Long-running worker subscriber | Natural request/response | Ratchet, Swoole, or external service |
A pattern I use on hybrid projects: MQTT from device to broker, then an EMQX rule or a small Node.js 26 LTS bridge publishes normalized events to a Laravel HTTP endpoint. The web app stays stateless PHP-FPM. The messaging tier handles connection churn. That split mirrors how multi-channel notifier architectures keep delivery mechanics out of controllers.
Choose WebSockets when you need a browser tab to stream live data and you control both ends. Choose MQTT when firmware teams, third-party hardware vendors, or mobile SDKs already standardise on it. Trying to force HTTP on a vendor that ships MQTT firmware costs more engineering time than standing up a broker.
How do you integrate MQTT with Laravel or PHP applications?
PHP request/response workers are the wrong place to hold a persistent MQTT connection. Run a dedicated consumer process instead, then hand events to queues your Laravel 13 app already understands.
Architecture that survives deploys
On production Laravel applications I maintain, long-lived processes run under systemd or Supervisor. They subscribe to MQTT topics, validate payloads, and dispatch Laravel jobs to Redis. The web tier never blocks on broker I/O. This matches how you'd integrate any high-volume webhook stream — same idempotency rules, same rate-limit and abuse patterns, different wire format.
# composer require php-mqtt/client (PHP 8.3+)
# app/Console/Commands/MqttConsumeCommand.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use PhpMqtt\Client\MqttClient;
use App\Jobs\ProcessTelemetryReading;
class MqttConsumeCommand extends Command
{
protected $signature = 'mqtt:consume';
protected $description = 'Subscribe to telemetry topics';
public function handle(): int
{
$client = new MqttClient(
config('mqtt.host'),
config('mqtt.port'),
config('mqtt.client_id')
);
$client->connect(
config('mqtt.username'),
config('mqtt.password')
);
$client->subscribe('site/+/+/telemetry', function ($topic, $message) {
$payload = json_decode($message, true);
if (! is_array($payload)) {
return;
}
ProcessTelemetryReading::dispatch($topic, $payload);
}, 1);
$client->loop(true);
return self::SUCCESS;
}
} Run it as a supervised service:
# /etc/systemd/system/mqtt-consumer.service
[Unit]
Description=Laravel MQTT consumer
After=network.target mosquitto.service
[Service]
User=www-data
WorkingDirectory=/var/www/app/current
ExecStart=/usr/bin/php artisan mqtt:consume
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target Idempotency and ordering
QoS 1 can deliver duplicates. Store a device message ID or a hash of topic plus timestamp in Redis before you write MySQL. Reject duplicates at the job layer. Ordering is per topic, not global. If sequence matters, include a monotonic counter in the payload and reject stale readings in application code.
For dashboards, push processed readings to the browser over Laravel Echo and Redis broadcasting. Keep MQTT on the server side only unless you have a compelling reason to expose brokers to browsers.
Bridging MQTT to business workflows
Once telemetry lands in your database, it is just data. Trigger automation rules when cold-storage temperature exceeds a threshold. Send SMS alerts through the same notifier pipeline you use for booking confirmations. On a trek-management platform like Adventure Third Pole Trek, GPS breadcrumbs might arrive over MQTT while staff manage bookings in Livewire — two channels, one source of truth in MySQL.
If you need a managed bridge without writing a consumer, EMQX rules can HTTP POST into Laravel routes protected by signed tokens, similar to payment gateway callbacks you already verify server-side. Treat those endpoints like webhooks: authenticate, validate schema, respond quickly, queue heavy work. The same discipline applies to API authentication choices elsewhere in your stack.
Key Takeaways
- MQTT for IoT messaging uses pub/sub topics and a central broker so devices and apps stay decoupled at scale.
- Default sensor streams to QoS 0 or 1; reserve QoS 2 for commands where duplicates cause real harm.
- Never expose an unauthenticated broker on port 1883 — TLS, ACLs, and per-device credentials are mandatory.
- Keep persistent MQTT connections out of PHP-FPM; run a supervised artisan consumer that dispatches Laravel jobs.
- Design topic hierarchies and idempotent job handlers before firmware teams ship incompatible naming schemes.
- Bridge MQTT into HTTP or queues when your main app is Laravel, WordPress, or another request-driven stack.
People Also Ask
Is MQTT secure enough for production IoT?
MQTT has no built-in encryption or authentication by itself. Production security comes from TLS on port 8883, strong client credentials, topic ACLs, and network isolation. Treat the broker like any public API surface. Patch it, monitor it, and rotate device passwords when hardware is decommissioned.
What is the difference between MQTT and CoAP?
MQTT runs over TCP and suits always-on gateways and Wi-Fi devices with steady connections. CoAP uses UDP and fits constrained microcontrollers on lossy links where connection overhead matters more. Many deployments use both: CoAP at the edge, MQTT from gateway to cloud.
Can MQTT work over cellular networks in Nepal?
Yes. NTC and Ncell data SIMs support TCP to port 8883 when APN settings allow it. Size payloads small, use QoS 1 sparingly, and set generous keep-alive values on unstable links. Test on the actual carrier before you deploy five hundred field units around Kathmandu Valley or the Terai.
How many connections can one Mosquitto instance handle?
A modest Ubuntu VPS with 2 GB RAM often handles a few thousand concurrent clients if messages are small and QoS stays low. Beyond that, profile CPU and file descriptors, then move to EMQX clustering or a managed cloud broker. Connection count matters more than message rate for sizing.
Build connected products without betting the farm on the wrong protocol
MQTT for IoT messaging earns its place when devices publish often, payloads stay tiny, and you need push semantics without polling a REST API all day. Stand up a secured broker, nail your topic contract, and bridge into the Laravel or PHP backend you already operate. Keep long-lived subscribers out of web workers, dedupe at the job layer, and monitor broker health like any other production dependency. If you are planning telemetry for logistics, agriculture, smart buildings, or a custom hardware integration, enterprise application development and API integration work can cover broker setup through dashboard delivery. See related builds on the portfolio or contact us to talk through architecture before you commit firmware to a topic scheme you cannot change later.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

