Python MQTT for IoT — Core Concepts

What MQTT Is

MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for constrained devices and unreliable networks. Created by Andy Stanford-Clark at IBM and Arlen Nipper in 1999, it was originally used to monitor oil pipelines via satellite. Today it is the dominant protocol for IoT communication.

MQTT follows a publish-subscribe pattern. Unlike HTTP where a client requests data from a specific server, MQTT decouples senders and receivers through a central broker. Publishers send messages to topics, and subscribers receive messages from topics they have registered interest in.

The Three Actors

Broker — The central server that receives all messages and routes them to subscribers. Popular brokers include Mosquitto (open source), HiveMQ, and EMQX. Cloud platforms like AWS IoT Core and Azure IoT Hub include MQTT broker functionality.

Publisher — Any device or application that sends messages. A temperature sensor publishes readings. A weather API publishes forecasts. Publishers do not know or care who receives their messages.

Subscriber — Any device or application that registers interest in topics. A dashboard subscribes to sensor data. An alert system subscribes to alarm topics. Subscribers do not know who publishes the data.

A single client can be both publisher and subscriber simultaneously.

Topic Hierarchy

Topics use forward slashes to create hierarchies, similar to file paths:

home/livingroom/temperature
home/livingroom/humidity
home/kitchen/temperature
home/garden/soil-moisture
office/server-room/temperature

Wildcards

Subscribers can use wildcards to match multiple topics:

  • Single-level wildcard (+) — Matches one level: home/+/temperature matches home/livingroom/temperature and home/kitchen/temperature but not home/livingroom/sensor/temperature.
  • Multi-level wildcard (#) — Matches everything below: home/# matches every topic starting with home/.

Quality of Service Levels

MQTT defines three delivery guarantee levels:

QoS 0 (At most once) — Fire and forget. The message is sent once with no confirmation. Fast but messages can be lost. Good for frequent sensor readings where a missed value does not matter.

QoS 1 (At least once) — The broker confirms receipt. If no confirmation arrives, the publisher resends. Messages are guaranteed to arrive but may arrive twice. Good for important data where duplicates are acceptable.

QoS 2 (Exactly once) — A four-step handshake ensures the message arrives exactly once. Slowest but no duplicates, no losses. Good for billing events or commands where duplication causes problems.

Most IoT applications use QoS 0 or QoS 1.

Python Implementation with paho-mqtt

The paho-mqtt library is the standard Python MQTT client:

import paho.mqtt.client as mqtt
import json
import time

def on_connect(client, userdata, flags, rc, properties=None):
    print(f"Connected with code {rc}")
    client.subscribe("home/+/temperature")

def on_message(client, userdata, msg):
    data = json.loads(msg.payload)
    print(f"{msg.topic}: {data['value']}°C")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.on_connect = on_connect
client.on_message = on_message

client.connect("localhost", 1883, 60)
client.loop_forever()

Publishing is equally straightforward:

import paho.mqtt.client as mqtt
import json
import time

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.connect("localhost", 1883, 60)

while True:
    payload = json.dumps({"value": 23.5, "unit": "celsius"})
    client.publish("home/livingroom/temperature", payload, qos=1)
    time.sleep(30)

Retained Messages and Last Will

Retained messages solve the “late subscriber” problem. When a message is published with the retain flag, the broker stores the last message on that topic. New subscribers immediately receive the most recent value without waiting for the next publish.

Last Will and Testament (LWT) handles ungraceful disconnections. When a client connects, it can register a “will” message. If the client disconnects without sending a proper disconnect packet (network failure, crash), the broker publishes the will message on behalf of the dead client:

client.will_set("home/sensor1/status", "offline", qos=1, retain=True)
client.connect("broker.example.com", 1883, 60)

This pattern is how IoT dashboards show device online/offline status.

Common Misconception

Despite “Message Queuing” being in the name, MQTT is not a message queue like RabbitMQ or Kafka. Messages are not stored for later consumption (except retained messages). If no subscriber is listening when a message arrives, it is gone. MQTT is a real-time pub-sub protocol, not a durable message store.

One thing to remember: MQTT’s combination of tiny message overhead, flexible topic routing, and configurable delivery guarantees makes it the go-to protocol for connecting resource-constrained IoT devices to the internet.

pythonmqttiotnetworking

See Also

  • Python Behavior Trees Robotics How robots make decisions using a tree-shaped rulebook that keeps them organized, like a flowchart that tells a robot what to do in every situation.
  • Python Bluetooth Ble How Python connects to fitness trackers, smart locks, and wireless sensors using the invisible radio signals all around you.
  • Python Circuitpython Hardware Why CircuitPython makes wiring up LEDs, sensors, and motors as easy as plugging in a USB drive.
  • Python Computer Vision Autonomous How self-driving cars use cameras and Python to see the road, spot pedestrians, read signs, and understand traffic — like giving a car human eyes and a brain.
  • Python Home Assistant Automation How Python turns your home into a smart home that reacts to you automatically, like a helpful invisible butler.