How to Subscribe to MQTT Topics
In this tutorial, you'll learn about How to Subscribe to MQTT Topics. We cover key concepts, practical examples, and best practices.
The Problem
Your MQTT client subscribes to a topic but never receives messages. You verified the publisher is working, yet on_message is never called. The broker log shows the subscription but messages are not delivered.
Quick Fix
Fix 1: Topic Mismatch
WRONG — subscribing to the wrong topic:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected")
client.subscribe("sensor/temperature") # publisher sends to "sensors/temperature"
def on_message(client, userdata, msg):
print(msg.payload)
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("localhost", 1883, 60)
client.loop_forever()
# (no messages received — topic path does not match)
RIGHT — match the exact topic:
client.subscribe("sensors/temperature")
# Now messages published to "sensors/temperature" are received
Fix 2: Wildcard Subscription
WRONG — using + (single-level) where # (multi-level) is needed:
client.subscribe("sensors/+") # matches "sensors/temp" but NOT "sensors/floor1/temp"
client.subscribe("sensors/#") # matches both "sensors/temp" AND "sensors/floor1/temp"
RIGHT — understand the wildcard semantics:
# "+" matches exactly one level
client.subscribe("sensors/+/temperature")
# Matches: sensors/kitchen/temperature, sensors/livingroom/temperature
# Does NOT match: sensors/temperature (need two levels)
# "#" matches all remaining levels (must be at the end)
client.subscribe("sensors/#")
# Matches: sensors/temperature, sensors/kitchen/temp, sensors/floor1/room1/humidity
Fix 3: QoS Mismatch
WRONG — publisher uses QoS 2 but subscriber uses QoS 0:
# Publisher:
client.publish("sensors/temp", "23.5", qos=2)
# Subscriber:
client.subscribe("sensors/temp", qos=0)
# (subscriber receives the message at QoS 0 — broker downgrades delivery)
RIGHT — subscribe with the same or higher QoS:
client.subscribe("sensors/temp", qos=2)
# (messages are delivered at the subscribed QoS level)
Fix 4: Not Looping (No Network Processing)
WRONG — subscribing but not calling loop_start or loop_forever:
client.connect("localhost", 1883, 60)
client.subscribe("sensors/temp")
# (no loop — the client never processes incoming network data)
RIGHT — start the network loop:
client.connect("localhost", 1883, 60)
client.subscribe("sensors/temp")
client.loop_start() # starts a background thread for network processing
# or
client.loop_forever() # blocks and processes network traffic
Fix 5: Message Handler Not Registered
WRONG — defining on_message after connecting:
client.connect("localhost", 1883, 60)
client.on_message = on_message # too late — messages may arrive before handler is set
RIGHT — set callbacks before connecting:
client.on_connect = on_connect
client.on_message = on_message
client.connect("localhost", 1883, 60)
Fix 6: Retained Messages
WRONG — expecting a retained message without subscribing first:
# Publisher sends: client.publish("sensors/temp", "23.5", retain=True)
# Subscriber connects, subscribes, and expects the retained message
# (retained message is delivered after subscription — this works correctly)
If you do not want retained messages, publish with retain=False.
Use DodaTech's MQTT Topic Explorer to subscribe to multiple topics simultaneously, view message hierarchies, and debug wildcard matching.
Prevention
- Double-check topic spelling and separator (
/vs.). - Test with a simple topic before using wildcards.
- Set callbacks before connecting.
- Call
loop_start()for background processing. - Match QoS between publisher and subscriber for reliable delivery.
Common Mistakes with client subscribe
- Misunderstanding that
Stringis[Char]with poor performance for large text operations - Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging
These mistakes appear frequently in real-world MQTT code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro