Back to all

Essential Guide to MQTT Topics and Wildcards

By now, you already know that MQTT message transmissions involve three parties – a publisher, a message broker, and at least one subscriber – and two transmissions: from publisher to broker, and from broker to subscriber. 

MQTT Publish Subscribe model

MQTT protocol uses a publish/subscribe (pub/sub) messaging model, which is an asynchronous type of communication. This means that after a publisher broadcasts a message, the broker relays the message to all subscribers of that topic.

MQTT communication model
MQTT communication model 2

Want to know more about MQTT topic structures, names, and when to use MQTT wildcards? Read this article to find out. If you need some background on MQTT, check out our articles about the basics of MQTT and MQTT quality of service (QoS) levels

What are MQTT Topics? 

MQTT topic is a filter the broker uses in MQTT message deliveries. Simply put, the broker filters all connected clients according to their subscriptions and forwards the message to these subscribers (clients).

Both publishers and subscribers can create MQTT topics. A topic exists as long as a client is subscribed to it. Otherwise, MQTT topics will be deleted. If the last subscriber to the topic disconnects and it does not have a persistent session, the topic also gets discarded. 

A persistent session means that messages will be saved on the broker even if subscribers lose their connection, ensuring no messages are missed. For more information on persistent sessions, check out this blog post.

MQTT Topic Structure Design and Names

MQTT topics are simple strings but are subject to an MQTT topic structure. Much like a computer’s file system, MQTT topics have a defined hierarchical structure, and they also use the forward slash (/) as a delimiter. 

In your computer’s file system, the forward slashes in a path indicate where a folder or file is located, but for MQTT topics, each forward slash denotes an MQTT topic name at a different topic level. Topic names are labels attached to a topic level that help the MQTT server accurately route messages.

Having this information about MQTT topic design and names, we will dive deeper into creating the topics. MQTT topics are only considered valid when UTF-8 characters are used. Also, a topic name must have at least one character. 

What to Note When Creating MQTT Topics

Case Sensitivity

You should know that MQTT topics are case-sensitive. For example, Abc/outlet01/alert02 and abc/outlet01/alert02 are two different topics. Because “Abc” and “abc” are identified as being different. This means that if you publish a message to Abc/outlet01/alert02 by mistake but the intended recipients subscribed to abc/outlet01/alert02, they will never get the message.

Note: MQTT topic names must match. 

The topic in the PUBLISH packet must match the topic the subscribers subscribed to. Otherwise, they will not receive the message.

Read our MQTT packet article to learn more about what it is, what types there are, and more.

Consistent MQTT Topic Names

Maintaining consistency when sending messages to different topic names is very important. Apart from ensuring the same casing, it is also essential to use the same MQTT topic structure within a project. So plan your MQTT topic structure before you send your first message!

Let’s say we wanted to publish a message to the topic alert02 for outlet01, we will use abc/outlet01/alert02. In this case, we should use the same topic structure and topic levels when publishing for alert03abc/outlet01/alert03

MQTT topics structure

To avoid incorrect or missed message deliveries, you should define a consistent topic structure and casing for all MQTT topics in your project. We know we have already mentioned this earlier, but it is that important in the MQTT world.

MQTT Topic Allowed Characters

As mentioned earlier, MQTT topics use UTF-8 characters and are considered valid if they contain at least one UTF-8 character. Almost any character or symbol on your keyboard would be MQTT topic-allowed characters, including blank spaces. 

That said, please avoid using blank spaces because this will cause chaos!

However, there are a few characters that you must avoid as they are reserved for other purposes, such as:

  • ‘+’ and ‘#’ – represent MQTT wildcards
  • ‘$’ – is a reserved character to be used at the start of the topic and it can only be defined by the broker.

We will explain wildcards and sys topics in the following few sections.

MQTT SYS Topics

MQTT SYS topics are reserved for MQTT brokers to broadcast system data like statistics or metadata about the brokers. An example would be getting the running status of a particular MQTT broker. 

While not explicitly defined in MQTT specification, MQTT SYS topics typically start with a $ and have $SYS as the first topic level. Some examples of sys topics include:

  • $SYS/broker/load/bytes/received
  • $SYS/broker/clients/total
  • $SYS/broker/messages/sent

Note: If you publish to an MQTT SYS topic, your message might not be delivered to your clients. 

For more information about sys topics, check out this document.

MQTT Topic Examples

We have covered a lot about topic structure and names, but let’s put things into perspective with a few MQTT topic examples. 

Company ABC is a fictional car company in the United States. They have multiple outlets across the country and also regularly send notifications to all outlets. Each outlet needs to subscribe to the respective topics to receive the notifications.

Incorrect MQTT topic example

  • Abc/outlet1/alert01/audiQ3
  • abc/Outlet01/alert1/audiQ3
  • $Abc/alert01/audiQ3
  • abc/Outlet1/alert01/audiQ3

The example above shows Company ABC using different MQTT topic structures across multiple levels and topic names with varying casings. With these MQTT topic examples, it would be difficult for Outlet01 to keep track of all the different structures when subscribing to topics. It also increases the risk of the outlet missing important messages from Company ABC.

Correct MQTT topic example 

  • abc/outlet01/alert01/audiQ3
  • abc/outlet01/alert01/bmwx3
  • abc/outlet01/alert02/audiQ3
  • abc/outlet01/alert02/bmwx3

In this example, we use a consistent MQTT topic structure and casing throughout the names. With consistency, it is a lot easier for Outlet01 to receive important messages from Company ABC without having to remember different structures and naming conventions.

However, defining topic filters might become more tedious if Outlet01 needs to subscribe to over 100 different alerts. In this situation, wildcards can be very handy.

What are MQTT Wildcards? 

MQTT wildcards are special characters that tell the broker you want to subscribe to any topic matching a specified pattern. It is also worth mentioning that in MQTT message deliveries, you can only use two wildcards – ‘+’ and ‘#.’

Important and worth repeating again and again: you should use MQTT wildcards when subscribing to topics, not when publishing a message.

When should you use MQTT Wildcards?

Wildcards can be helpful on many occasions, the most common being when there are several topic filters with similar names. In MQTT, subscribers can define more than one topic filter, but in this case, with multiple similar topic names, it can get tedious to define each filter. 

Using the same example earlier, if Outlet01 from Company ABC needs to subscribe to all updates from 50 other outlets, it is very time-consuming to list each topic. That is where MQTT wildcards come in.

As mentioned earlier, MQTT only uses two wildcards – ‘+’ and ‘#.’ Let’s find out what each wildcard means and when you should use them.

Plus Sign (+) Wildcards – Single level wildcard

The plus sign (+) wildcard is a single-level wildcard that matches any MQTT topic name within a specified topic level. This means that you can use this in place of defining various topic names within a single level.

It is important to note that the plus sign wildcard should occupy an entire topic level. It cannot be used as a suffix to other MQTT topic names – we will explain how this works in the next section.

Example of + Wildcards

Let’s use the same example of Outlet01 in Company ABC, which wants to receive notifications for all alerts.

Example without + wildcard

  • abc/outlet01/alert01/audiQ3
  • abc/outlet01/alert02/bmwx3
  • abc/outlet01/alert03/audiQ3
  • abc/outlet01/alert04/bmwx3

Without the + wildcard, Outlet01 will need to list all topic names to receive the messages from the different alerts. It can get extremely tedious and time-consuming, especially if there are hundreds of alerts.

Incorrect example with + wildcard

  • abc/outlet01/alert+/audiQ3

As I mentioned earlier, you should refrain from using the plus sign wildcard as a suffix. In this example, we use the + wildcard at the end of the word outlet. This usage is invalid as the plus wildcard only occupies part of the topic level.

Correct example with + wildcard

  • abc/outlet01/+/audiQ3
  • abc/outlet01/alert01/+

Outlet01 can use the + wildcard in this case and only needs to define one topic name in the filter. With the abc/outlet01/+/audiQ3 topic filter, a receiver will get all notifications from all alerts with the same MQTT topic structure. In this case, the subscriber will receive messages for all audiQ3 topics, like abc/outlet01/alert01/audiQ3, abc/outlet01/alert02/audiQ3, and so on.

With abc/outlet01/alert01/+, Outlet01 will receive all alert01 notifications for all car models, which includes abc/outlet01/alert01/audiQ3, abc/outlet01/alert01/bmwx3, and so on.

Hash (#) Wildcards 

Unlike the plus sign, the hash (#) wildcard can match more than one topic level, but it must be used as the last level. In this case, you can use it to find nested topics that match your search criteria.

Similarly to the ‘+’ wildcard, the ‘#’ wildcard cannot be used as a suffix and must occupy the whole topic level. We will cover some examples of how to use # wildcards properly.

Example of # Wildcards

For this example, we are using the same example of Company ABC’s Outlet01, which wants to receive updates of all alerts for the Audi Q3 model.

Example without # wildcard

  • abc/outlet01/alert01/audiQ3
  • abc/outlet01/alert02/audiQ3
  • abc/outlet01/alert03/audiQ3
  • abc/outlet01/alert04/audiQ3

Similar to the earlier example, Outlet01 would need to list out each topic filter for every alert, which is tedious. A ‘#’ wildcard would save you loads of time if used correctly.

Incorrect example with # wildcard

  • abc/outlet01/alert#/audiQ3
  • abc/outlet#/alert01/audiQ3
  • abc/#/alert01/audiQ3

The ‘#’ wildcard must occupy an entire topic level and be the last level specified, so the examples above are invalid. Now, let’s look at correctly using the ‘#’ wildcard.

Correct example with # wildcard

  • abc/#
  • abc/outlet01/#
  • abc/outlet01/alert01/#

These examples are all valid, but Company ABC will receive different messages:

  • abc/# – Gets all messages sent to the abc topic, as well as other topics like abc/outlet01/alert01/audiQ3, abc/outlet03/alert05/audiQ3 and so on.
  • abc/outlet01/# – Only gets messages for topics related to outlet01 like abc/outlet01/alert01/audiQ3, abc/outlet01/alert03/bmwx3 and so on.
  • abc/outlet01/alert01/# – Only gets messages for topics related to outlet01/alert01 like abc/outlet01/alert01/audiQ3, abc/outlet01/alert01/bmwx3 and so on.

Although # wildcards are very useful in defining multiple topic levels at once, you should not use them to subscribe to all topics. Doing this will overload your clients as they will receive all published messages from all existing topics.

It is just one of the reasons why all practical systems implement access control to ensure that even if an MQTT client is subscribed to all topics, it will get messages only from the topics it can access.

However, in this case, the load on the system will still be significant. That is why we recommend subscribing to those topics from which you really want to receive messages.

Note: If you want to subscribe to all topics using the ‘#’ wildcard, and one of the topics includes the ‘$’ special character, you will not get any message from the topic containing ‘$.’

How MQTT Wildcards Work with QoS Levels 

You should already know that publishers and subscribers can have different QoS levels, but the broker will follow the lowest QoS level set by either publisher or subscriber. 

MQTT wildcards are used when subscribing to topics, not when publishing a message. The broker will still follow the lowest QoS level, but the message will be discarded if there are no subscribers for a particular topic.

For example, Company ABC is a publisher with a QoS level of 1 (QoS1), and Outlet01 is a subscriber with a QoS level of 2 (QoS2). The MQTT broker here will only deliver messages with QoS 1 – at most once. 

However, if Outlet01 subscribes to abc/outlet01/alert01/# with Qos level 2 (QoS2), but Company ABC publishes to bc/outlet01/alert01/audiQ3 with QoS level 1 (QoS1), the Outlet01 will receive the message with QoS1.

Key Takeaways

Let’s recap everything we’ve learned about MQTT topics, topic structure, and wildcards.

  • Topics only exist if there are a subscriber and/or stored messages for that topic.
  • Topic structures use a forward slash ‘/’ as a delimiter, much like a computer file path.
  • Topic names are case-sensitive and should follow a consistent naming convention.
  • Topic names must include at least one character and can consist of any UTF-8 characters, except ‘$,’ ‘*,’ ‘+,’ and ‘#.’
  • ‘$’ denote sys topics used by MQTT brokers to publish data on broker performance.
  • ‘+’ and ‘#’ are single and multi-level wildcards.
  • Topic wildcards only apply when subscribing to a topic, not when publishing messages.

With this information, you have all you need to use MQTT topics and wildcards in your projects. If you need help setting up your MQTT project, we recommend using the Pro Edition for Eclipse Mosquitto

If you do not wish to purchase the pro version yet, there is a free 14-day trial. You can test basic MQTT broker scenarios using the trial, access existing REST APIs, and more. Sign up for it here.

Click to rate this post!
[Total: 3 Average: 4.7]
About the author
Avatar photo

Roger Light

Co-Founder and Senior Developer at Cedalo, Eclipse Mosquitto Lead Developer

Roger has a background in Electronic Engineering academic research focusing on the design of scientific optical imaging sensors, accompanying control and acquisition systems, and other embedded designs.

He has 6 years of Academic teaching responsibility, teaching semiconductor chip design, embedded design, and programming.

Roger started Mosquitto as a hobby project in 2009, which gained rapid popularity and contributed to the widespread adoption of MQTT as an IoT protocol. He also developed an MQTT client library in Python, and both projects became part of the Eclipse Foundation in 2014/15. In 2018, Roger joined Cedalo to develop Mosquitto further, starting with implementing MQTT v5.0 support.

Newsletters icon

Subscribe for monthly updates