Shared subscriptions let multiple MQTT clients consume messages from the same topic, but only one client gets each message.

Here’s a simple MQTT scenario. Imagine a fleet of IoT devices sending temperature readings to a central broker. We want to process these readings to detect anomalies.

# Publisher (e.g., an IoT device)
import paho.mqtt.client as mqtt
import time

broker_address = "localhost"
port = 1883

client = mqtt.Client("publisher_1")
client.connect(broker_address, port)

topic = "sensor/temperature/room1"
temperature = 22.5

while True:
    message = f"{temperature},{time.time()}"
    client.publish(topic, message)
    print(f"Published: {message} to {topic}")
    temperature += 0.1
    time.sleep(5)

Now, let’s set up two subscribers to process these temperature readings. Without shared subscriptions, both subscriber_a and subscriber_b would receive every message published to sensor/temperature/room1. This would mean duplicate processing, which is usually undesirable.

# Subscriber A
import paho.mqtt.client as mqtt

broker_address = "localhost"
port = 1883

def on_message(client, userdata, msg):
    payload = msg.payload.decode("utf-8")
    print(f"Subscriber A received: {payload}")

client_a = mqtt.Client("subscriber_a")
client_a.on_message = on_message
client_a.connect(broker_address, port)

topic = "sensor/temperature/room1"
client_a.subscribe(topic)
print(f"Subscriber A subscribed to {topic}")

client_a.loop_forever()
# Subscriber B
import paho.mqtt.client as mqtt

broker_address = "localhost"
port = 1883

def on_message(client, userdata, msg):
    payload = msg.payload.decode("utf-8")
    print(f"Subscriber B received: {payload}")

client_b = mqtt.Client("subscriber_b")
client_b.on_message = on_message
client_b.connect(broker_address, port)

topic = "sensor/temperature/room1"
client_b.subscribe(topic)
print(f"Subscriber B subscribed to {topic}")

client_b.loop_forever()

In this setup, if the publisher sends "22.5,1678886400", both Subscriber A and Subscriber B would print: Subscriber A received: 22.5,1678886400 Subscriber B received: 22.5,1678886400

This is where shared subscriptions come in. They allow us to create a "consumer group" for a topic. When clients subscribe to a topic using a shared subscription syntax, the MQTT broker distributes the messages among the clients in that group.

The syntax for a shared subscription is $share/<group_name>/<topic_filter>.

Let’s modify Subscriber A and B to use a shared subscription with a group named temperature_processors.

# Subscriber A (Shared)
import paho.mqtt.client as mqtt

broker_address = "localhost"
port = 1883

def on_message(client, userdata, msg):
    payload = msg.payload.decode("utf-8")
    print(f"Subscriber A (Shared) received: {payload}")

client_a = mqtt.Client("subscriber_a_shared")
client_a.on_message = on_message
client_a.connect(broker_address, port)

shared_topic = "$share/temperature_processors/sensor/temperature/room1"
client_a.subscribe(shared_topic)
print(f"Subscriber A subscribed to {shared_topic}")

client_a.loop_forever()
# Subscriber B (Shared)
import paho.mqtt.client as mqtt

broker_address = "localhost"
port = 1883

def on_message(client, userdata, msg):
    payload = msg.payload.decode("utf-8")
    print(f"Subscriber B (Shared) received: {payload}")

client_b = mqtt.Client("subscriber_b_shared")
client_b.on_message = on_message
client_b.connect(broker_address, port)

shared_topic = "$share/temperature_processors/sensor/temperature/room1"
client_b.subscribe(shared_topic)
print(f"Subscriber B subscribed to {shared_topic}")

client_b.loop_forever()

Now, when the publisher sends "22.6,1678886405", you might see output like this: Subscriber A (Shared) received: 22.6,1678886405 or Subscriber B (Shared) received: 22.6,1678886405

Crucially, only one of them receives the message. The broker has distributed the load. If you add a third subscriber, subscriber_c_shared, to the same group, messages will be distributed among A, B, and C.

The key here is that the $share prefix and the group name are interpreted by the MQTT broker, not the clients. The clients simply subscribe to a topic string that happens to start with $share/group_name/. The broker then manages the distribution logic. This allows for dynamic scaling: if you have too much load for two consumers, you can spin up a third or fourth subscriber_x_shared client, and the broker will automatically start sending messages to them, balancing the load across the available members of the temperature_processors group.

The broker maintains the state for each shared subscription group. When a message arrives for a topic that has active shared subscriptions, the broker selects one client from the group that is subscribed to that topic (or a matching topic filter) and forwards the message to it. The selection algorithm can vary between brokers, but it’s typically designed to distribute messages as evenly as possible. If a client disconnects, the broker will re-distribute its assigned messages to the remaining clients in the group.

A common misconception is that shared subscriptions are just a client-side filtering mechanism. They are not. The broker actively participates in the message routing. The broker is the one ensuring that only one consumer in the group gets a particular message. This is why you need to ensure your MQTT broker actually supports MQTT 5.0 features for shared subscriptions. Older brokers might not understand the $share prefix at all.

The power of shared subscriptions lies in their ability to decouple message producers from message consumers and enable horizontal scaling of consumer applications without altering the producer logic. You can have any number of clients join or leave a shared subscription group dynamically, and the broker will adapt the message distribution accordingly.

The next concept to explore is how Quality of Service (QoS) levels interact with shared subscriptions, particularly regarding message acknowledgment and redelivery if a consumer fails.

Want structured learning?

Take the full Mqtt course →