Skip to Content

The Dashboard in front of you, and the five words underneath it

learn the map first
EMQX Guide · Part 2

The Dashboard in front of you, and the five words underneath it

EMQX is installed and it is running. This part does the two things that make every later part shorter. First, a walk around the Dashboard — what each sidebar group is for, what the front page is actually counting, and where the version number hides — so that when a later part says “go to Access Control,” you already know where that is. Second, the mental model underneath the interface: topic, QoS, retained, will and session. Those five words are what you fall back on the day a device is fine on Monday and flaky on Tuesday.

18083
The port the Dashboard listens on by default. Home Assistant's Ingress reaches the same page without it
2 wildcards
The + fills exactly one level. The # takes every level that is left, and only at the end
3 QoS levels
Three different guarantees at three different costs. Not a quality ladder you climb
The map goes in first

Learning the building before there is smoke in it

EMQX gathers everything involved in running a broker into one admin interface, and that interface is called the Dashboard. Who is connected right now. Whether a subscription actually took. Whether messages are going out at all. If you try to answer those from config files and log lines alone, you have thrown away about half of your debugging loop before you started. The Dashboard answers all three with a handful of cards.

So the point of this first half is not to configure anything. It is to build a map in your head: which sidebar group covers what, where the important numbers sit on the front page, and where to read the version and the license state. Every part after this one — authentication, ACL, listeners, connectors, monitoring, backup — opens by naming a menu path. You want to already know where that path starts, rather than hunting for it the first time something is broken.

In plain terms

The Dashboard is the CCTV room of a warehouse, not the warehouse. The forklifts keep moving, the deliveries keep arriving and the doors keep opening whether or not anybody is sitting at the monitors. You go in there to see what is happening, not to make it happen.

That is worth fixing early because it changes how you read a problem. The Dashboard is only a visual layer over EMQX. The broker sends and receives MQTT messages exactly as usual whether or not you have the Dashboard open. If the Dashboard will not load, your devices are very probably still talking to each other — you have lost the window, not the broker.

Two ways in, one page

The Dashboard listens on HTTP port 18083. There are two routes to it and both land on the same page.

  1. Route 1

    Through Home Assistant's sidebar

    In Home Assistant's left sidebar, find the EMQX icon — that is the Ingress entry point — and click it. The Dashboard opens inside Home Assistant, and you did not have to know the host's address or the port.

  2. Route 2

    Straight at the port

    Open the address in a browser yourself. The host part is whichever machine EMQX is running on:

    http://<host>:18083

    This is the route you want when the host sits on a different subnet from the browser you are using, or when Home Assistant itself is the thing you are trying to debug.

  3. First login

    Sign in, then change the password before anything else

    The first sign-in uses the default account:

    admin/public — the factory default, and it is the same on every EMQX install in the world

    EMQX prompts you to change it. Do that immediately, to a password of your own. Part 1 of this series covers the change itself. A broker left on the default admin password is a broker anybody who can reach port 18083 can reconfigure.

  4. Then

    Walk the sidebar end to end, once, with nothing broken

    Go down the left column from Monitoring, through Access Control and Integration, all the way to System, and write one line for yourself on what each group is for. Then come back to Monitoring → Cluster Overview and take the whole picture in again. Ten minutes of this now is worth an hour later.

Signing in lands you on Cluster Overview. That page is the foundation the rest of the Dashboard rests on: how many connections and subscriptions exist right now, how fast messages are flowing in and out, and how many nodes the cluster has. It is the first thing to glance at before any troubleshooting, and the next section is about reading it properly.
What the front page counts

Cluster Overview, and where the version hides

The Dashboard home page is Cluster Overview. Two cards sit across the top half, and between them they carry the numbers you will check most often.

  • Message Rate. How many messages the system takes in and sends out per second, shown live. This is the card that tells you whether anything is moving at all.
  • Connections / Subscriptions / Topics. The current connection count, the total number of subscriptions, and the number of unique topics. These update the moment a connection changes, so plugging a device in and watching the connection count tick up is a perfectly good sanity check.

Below those sits a time-series chart, and it has a time range you can pick. Six ranges are offered: the past 1 hour, 6 hours, 12 hours, 1 day, 3 days or 7 days. That is how you tell a spike from a trend — a connection count that sags every night at the same hour looks like nothing on the 1 hour view and is obvious on the 7 day one.

If the chart is carrying too much history to read, use Reset Monitoring Data. It clears what came before and starts accumulating again from now. That is the right move after a big configuration change, when the old numbers describe a system that no longer exists.

The Nodes tab, and the version number

Switch to the Nodes tab and you get every EMQX instance in the cluster, one row each: name, status, uptime, connection count, version, Erlang process count, and memory and CPU usage. A node drawn in gray has stopped. Click a node's name and you open its detail view, with system paths, log paths and finer-grained statistics.

That version column is the answer to a question you will need more than once. This guide is written against EMQX 5.8.9, Open Source edition, and the most direct way to confirm what you are actually running is:

Monitoring → Nodes — the version column, in the row next to the node name

Write it down somewhere. Menu paths and screen wording drift between EMQX versions, and the first thing anybody helping you will ask is which version you are on.

One node is the normal case at home. Every EMQX instance is one node. An add-on install on a single machine runs a single node, and that is not a degraded setup — several nodes only appear when you build a cluster on purpose. The Nodes tab is still worth visiting on a one-node install, because it is where the version and the resource usage live.
Nobody knows who is listening

Publish, subscribe, and the broker in the middle

That is the tour. The rest of this part is the model underneath it, and it starts with the one idea the whole protocol is built on.

At the heart of MQTT is the publish/subscribe model, which splits the work into three roles. A publisher sends messages out under a topic. The broker — the EMQX you just toured — routes and filters every message. A subscriber subscribes only to the topics it cares about.

The point, and it is easy to read past: a publisher and a subscriber never need to know that the other exists. The only contract they share is the topic string. When the broker receives a message on a topic, it hands that data to every client currently subscribed to that topic, at the same time.

flowchart LR
  P["The living-room sensor
publishes to
living-room/temperature"] --> B["EMQX
the broker in the middle"] B --> S1["Home Assistant,
subscribed to
living-room/temperature"] B --> S2["A wall display,
subscribed to
living-room/temperature"] B --> S3["A logger, subscribed to
living-room/#"]
One publisher, three subscribersThe sensor on the left hands one message to the broker and its job ends there. The three boxes on the right each get their copy at the same moment, and the sensor is never told they exist.

That is why adding a device, or adding a screen, disturbs none of the endpoints already running. The wall display in that picture can be unplugged for a fortnight and the sensor's code does not change by a character.

Worth pinning down: every endpoint is a client. A sensor is a client. A phone app is a client. Home Assistant is a client. There is no separate category of software that gets to be more important; the broker sees connections, and each connection brings its own parameters — keepalive, and how long its session is held — which the last part of this article covers.

If it helps, it is a noticeboard in a corridor rather than a phone call. You pin a note under the heading living room, temperature and walk off. You do not know whether three people read it or nobody did, and you do not wait to find out. Anybody who cares about that heading comes and reads it, and nobody has to be introduced to anybody.

Topics and the two wildcards

Where one wrong character means silence

A topic is a UTF-8 string, split into levels by a forward slash /. In living-room/temperature, the level temperature sits under the level living-room. A publisher always sends to one specific topic. A subscriber, on the other hand, can use a wildcard to subscribe to many topics at once.

MQTT gives you exactly two wildcards, and they are not interchangeable.

The single-level wildcard: +

It matches exactly one level. Subscribing to living-room/+/temperature receives living-room/east/temperature and living-room/west/temperature. It does not receive living-room/east/upper/temperature, because east/upper is two levels where the + allows one.

The multi-level wildcard: #

It matches any number of levels, and it must come last. Subscribing to living-room/# receives living-room, living-room/temperature and living-room/east/upper/temperature alike — everything from that point down.

Two rules govern both of them, and breaking either one is the usual reason a subscription sits there receiving nothing.

  • Wildcards are for subscribing only, never for publishing. You cannot publish to living-room/+/temperature. A published message always names one exact topic.
  • Each wildcard fills a whole level, and in the case of #, comes last. sensor/#/temp puts the # in the middle, which is not a legal filter.
flowchart TD
  M["One message, published to
living-room/east/upper/temperature"] M --> Q1{"Matched against the filter
living-room/+/temperature"} M --> Q2{"Matched against the filter
living-room/#"} Q1 -->|"no, + fills exactly one level"| N["This subscriber
receives nothing"] Q2 -->|"yes, # takes every level left"| Y["This subscriber
receives the message"]
Same message, two filters, two outcomesOne published topic is tested against both wildcards. The left branch is the + filter and it ends in nothing delivered; the right branch is the # filter and it ends in delivery. The message itself is identical either way — the difference is entirely in what the subscriber asked for.
Subscription filterReceivesDoes not receive
living-room/+/temperature living-room/east/temperature
living-room/west/temperature
living-room/east/upper/temperature — two levels where + allows one
living-room/# living-room
living-room/temperature
living-room/east/upper/temperature
Anything that does not start with the living-room level
sensor/#/temp Nothing. This is not a legal filter The # is in the middle, and it is only allowed at the end
In plain terms

Think of a filing cabinet with drawers inside drawers. The + says “any one drawer at this depth, then keep going” — you still have to name what comes after it. The # says “this drawer and everything inside it, however deep it goes” — and once you have said that, there is nothing left to say, which is exactly why it has to be the last thing you write.

Copy topic strings, do not retype them. Topics are compared character for character, and there is no near miss and no helpful error. A subscriber on livingroom/temperature and a publisher on living-room/temperature will sit there in perfect silence, both of them apparently working, forever.
Three guarantees, three costs

QoS is a choice about consequences, not about quality

QoS stands for quality of service. It is a reliability setting carried by each message on its own, and it has three levels. Read the guarantees as they are written, because the shorthand people reach for — “higher is better” — is not what they say.

QoSGuaranteeScenario
0 At most once, may be lost Telemetry such as temperature and humidity, where losing one reading does no harm
1 At least once; duplicates are possible Switch commands, though a duplicate copy may arrive
2 Exactly once, never duplicated Payment and accounting logic, where a duplicate is never acceptable

QoS 1 is the level that catches people out. Its guarantee is at least once, and the price of that guarantee is that duplicates are possible. A switch command sent at QoS 1 may genuinely arrive twice. If your receiving end toggles rather than sets, that is a light that ends up off when you asked for on.

flowchart TD
  A["Choosing the QoS
for one message"] --> B{"Does losing a single one
of these do any harm?"} B -->|"no"| Q0["QoS 0, at most once.
May be lost.
Temperature and humidity readings"] B -->|"yes"| C{"Is a duplicate copy
ever acceptable?"} C -->|"yes"| Q1["QoS 1, at least once.
Duplicates are possible.
Switch commands"] C -->|"no"| Q2["QoS 2, exactly once.
Never duplicated.
Payment and accounting logic"]
Two questions, three endingsAnswer no to the first question and the walk stops at QoS 0 immediately; only a yes carries on to the second question, which is the one that separates QoS 1 from QoS 2.

There is a cost attached, and it is the reason QoS 2 is not simply the right answer everywhere. The higher the QoS, the more negotiation and transfer it costs. QoS 0 is a good deal for everyday telemetry — a temperature reading that goes missing is replaced by the next one thirty seconds later. Keep 1 and 2 for devices whose control has to be guaranteed.

In plain terms

It is the difference between dropping a postcard in the box, sending something the postman keeps re-delivering until somebody signs for it, and a courier who checks a reference number both ways before handing it over. The postcard is not a worse product than the courier. It is a different arrangement, and you would not pay courier rates to tell your neighbor it is raining.

The cheapest fix for duplicates is at the receiving end. If duplicates are unacceptable, you have two routes: move to QoS 2, or make the receiver idempotent — that is, build it so that handling the same message twice produces the same result as handling it once. “Set the light to on” is idempotent. “Toggle the light” is not.
Session, retained, will

What survives a disconnection, and what does not

Five more terms. The first four explain almost every “why did the state come back wrong after a reboot” question you will ever ask; the fifth is about spreading load rather than surviving anything.

Session

A session is the state a client and the broker keep between them, and it is what makes QoS 1 and 2 work correctly at all. Which flag controls it depends on the protocol version the client speaks:

  • MQTT 5.0 controls a session with clean start and the session expiry interval.
  • MQTT 3.1.1 uses the clean session flag instead.

With a clean session, the session is discarded the moment the client disconnects. If you want the QoS 1 and 2 messages from the offline period to be delivered after the client reconnects, you want a persistent session rather than a clean one.

A persistent session does not queue everything. Only QoS 1 and 2 messages on a session that is being kept are queued while the client is offline. Plain QoS 0 is not kept at all. Publishing state at QoS 0 and then expecting a persistent session to replay it after an outage is a combination that quietly does nothing.

Keepalive

Keepalive is how long the client promises to go between control packets sent to the broker. If the broker hears nothing for longer than that, it treats the connection as dropped. When you find yourself wanting to adjust how quickly a flaky device is declared offline, keepalive is the number you are actually adjusting.

Retained messages

Mark a message as Retain and the broker stores the latest message for that topic. Any new subscriber to that topic receives it immediately, without waiting for the publisher to publish again. The cost is that only the latest message per topic is kept — a retained publish replaces the retained message before it, so this is a way to hold current state, not a history.

flowchart TD
  P["A publish to
living-room/humidity"] --> B["Delivered to every client
subscribed at that moment"] B --> R{"Was the message
marked Retain?"} R -->|"no"| N["Nothing is stored. A client that
subscribes later sees nothing
until the next publish"] R -->|"yes"| K["The broker keeps it as the latest
message for that topic, replacing
whatever it held before"] K --> L["A client that subscribes an hour later
receives it the moment it subscribes"]
Where a message goes after it is deliveredBoth branches deliver to whoever was already subscribed — that box sits above the question. The no branch ends there in one box; the yes branch has a second box after the storing step, because being kept and being handed to a later subscriber are two separate events.

To clear a retained message, publish an empty message to that topic. There is no delete button in the protocol; an empty payload on the same topic is the delete.

In plain terms

A retained message is the note stuck on the fridge door. Whoever walks into the kitchen next reads it, whether they were there when it was written or not. Write a new note and you take the old one down first — there is only ever one note on that door. Taking the note down and leaving nothing behind is the empty message.

Will messages

A client sets a will when it connects — a topic plus a payload. When that client drops unexpectedly, the broker publishes that will to the subscribers on its behalf, so everyone else knows straight away that its state has changed. It is the message you leave with the broker in advance, to be sent if you stop answering.

Will and Retain can be combined. When you set the will you can tick Retain as well, and then, besides publishing the will on an unexpected disconnect, the broker also stores it as a retained message — so a client that subscribes afterwards gets the offline state right away rather than waiting.

Shared subscriptions

A shared subscription takes this form:

$share/<group>/<topic> — the group name is yours to choose; the topic part is the ordinary filter

It spreads the message load evenly across the subscribers in one group — round_robin by default — instead of giving every one of them a duplicate copy. Within one group, each message is received by exactly one client, chosen by the strategy in force. Separate groups each receive their own copy. To raise throughput or add redundancy, split the work across several subscribers so each handles its own share.

Prove it in the browser

Twenty minutes with the built-in WebSocket client

Everything above is words until you watch a message move. The Dashboard has a WebSocket test client built into it, which means you can be both the publisher and the subscriber without installing anything, wiring up a device, or writing a line of code. Run these four steps once and the terms stop being abstract.

  1. Step 1

    Open the WebSocket test client

    In the EMQX Dashboard, go to the Diagnose group and find the built-in visual WebSocket client among the diagnose tools. It connects to your own broker as MQTT over WebSocket — it is a real client, not a simulation, and everything it does shows up in the counters on Cluster Overview.

  2. Step 2

    Subscribe to a topic

    Add a subscriber and subscribe to a topic. Use this one, so it matches the examples above:

    living-room/humidity

    Do not attach anything practical to it yet. The whole point of this step is to get a direct impression of subscribe, then receive.

  3. Step 3

    Publish a message to it

    Switch to the publisher role, type living-room/humidity as the topic and a number as the payload, then send it. Watch whether the subscriber receives it straight away. If it does, you have just done, by hand, the whole of what the broker exists to do.

  4. Step 4

    Now try QoS and Retain

    Change the publish QoS to 1 and tick Retain, then send again. Now unsubscribe, and subscribe to living-room/humidity a second time. The retained message arrives immediately, without anybody publishing anything new. That is the fridge-door note, and it is the behavior that explains why Home Assistant can show a sensor value seconds after a restart.

Wildcards are worth one extra minute here. Subscribe to living-room/# in one subscriber, publish to living-room/east/upper/temperature, and watch it arrive. Then subscribe to living-room/+/temperature instead and publish the same topic again. Nothing arrives, and you have proved the rule to yourself rather than taking it on trust.
This is the intuition pass, not the full demonstration. Part 3 of this series does the proper first connection, where you verify these terms against a real client instead of the browser. Part 4 covers listeners and TLS, and Part 6 covers the Home Assistant integration — and all three assume the vocabulary you have just used by hand.
When it does not behave

Eight symptoms, and what each one actually means

Four of these are Dashboard problems and four are protocol problems, and telling those two apart is most of the work.

The Dashboard side

  1. 1

    You can sign in, but the Dashboard will not open

    Check which route you are on. Ingress from the Home Assistant sidebar and port 18083 are two different paths to the same page, and they fail for different reasons. If the host is on another subnet from your browser, go direct with http://<host>:18083 instead of through Ingress.

  2. 2

    You cannot find the version anywhere

    Go to Monitoring → Nodes. The version column beside the node name is the version now running. On the install this guide is written against, expect 5.8.9.

  3. 3

    A sidebar entry you read about is missing

    Advanced features such as Delayed Publish and Alarms are not shown by default in the Open Source edition, and License and SSO need EMQX Enterprise. This is normal, not a fault. Before you go looking for a broken setting, check whether the feature belongs to the edition you are running.

  4. 4

    The numbers on the home page look stuck

    The Overview chart has a time range you can pick, so first make sure you are not looking at 7 days when you want the last few minutes. To start accumulating from scratch, use Reset Monitoring Data.

The protocol side

  1. 5

    You subscribed to a wildcard topic and nothing arrives

    Check two things in order. First, that + and # are being used only on a subscription, never on a publish. Second, that they sit in a legal position: sensor/#/temp, for example, puts the # in the middle, and that is not valid. After that, compare the publisher's topic and the subscriber's filter character by character.

  2. 6

    Messages look like they are arriving twice

    QoS 1 is by nature at least once, which means duplicates are possible — this is the protocol working as specified, not a bug in your setup. If duplicates are unacceptable, either move to QoS 2 or make the receiving end idempotent.

  3. 7

    There is no earlier state after a restart

    Retain was not set. Mark the state message as Retain so the broker holds the latest one, or switch to a persistent session so the QoS 1 and 2 data from the offline period is delivered afterwards. Those are two different mechanisms for two different needs: Retain serves whoever subscribes next, a persistent session serves one particular client coming back.

  4. 8

    The session is not kept after a disconnect

    Only QoS 1 and 2 messages on a session that is being kept are queued while the client is offline; plain QoS 0 is not kept at all. If you want data from the offline period delivered later, use a persistent session rather than a clean session — and publish that data at QoS 1 or 2, or there will be nothing to queue.

Questions people ask

The ones that come up every time

Does the Dashboard have to be running for MQTT to work?
No. EMQX sends and receives MQTT messages as usual even with the Dashboard closed. The Dashboard is only an admin interface — the convenience layer for working, watching and debugging visually. If it will not load, that is a problem with your window onto the broker, not necessarily with the broker.
Where do I switch the language?
Usually in the user menu in the top right, or in preferences. Changing the language does not affect how the broker behaves at all; it is purely a matter of convenience.
What is a “node” on the Overview page?
Every EMQX instance is one node. A home add-on install usually runs a single node; several nodes only come with a cluster. The Nodes tab shows the status, version and system resources of each node, and a node drawn in gray has stopped.
Why are some features missing from my sidebar?
Most advanced data integration and security features belong to EMQX Enterprise, the paid edition. Open Source 5.8.9 does not show those entries, and that is not a configuration error. License and SSO are the two clearest examples: they are Enterprise only, and the System group in Open Source simply does not have those pages.
Does MQTT always need a broker?
Yes. MQTT is a protocol built on a broker forwarding messages. Without one there is no third party between two endpoints to route anything, and it is no longer MQTT. Your EMQX is that broker.
How does a retained message differ from an ordinary one?
An ordinary message goes only to whoever is subscribed at that moment. A retained message is kept by the broker, so any client that subscribes to the same topic afterwards also receives it immediately. Only the latest message per topic is kept, so it holds current state rather than history.
Can a will message and Retain be used together?
Yes. When you set the will you can tick Retain as well. Then, besides publishing the will on an unexpected disconnect, the broker also stores it as a retained message, and anyone subscribing later gets the state right away.
With a shared subscription, who receives each message?
Within one $share/<group>/ group, each message is received by exactly one client in the group, chosen by the strategy in force — round_robin by default. Separate groups each receive their own copy. That makes it a good fit for spreading load across several workers, or for adding redundancy.
Can I publish to a topic containing + or #?
No. Both wildcards can be used only to subscribe, never to publish. A published message always names one exact topic with no wildcard in it. If you find yourself wanting to publish to living-room/+/temperature, what you actually want is to publish to each of the real topics in turn, or to restructure the topic tree so one publish covers the case.
Should I just use QoS 2 for everything and stop worrying?
No, and not because QoS 2 is unreliable — it is exactly once and never duplicated. The reason is cost: the higher the QoS, the more negotiation and transfer it takes. QoS 0 is a good deal for everyday telemetry, where losing one reading among hundreds does no harm. Keep 1 and 2 for the devices whose control has to be guaranteed. Choose per message, because QoS is carried by each message on its own.
Next

Where to go from here

keep going

You have the map and the vocabulary. Now connect something real.

Part 3 takes the terms you have just used in a browser tab and makes them do work: a genuine first connection from a real client, and then authentication — deciding who is allowed to connect to your broker at all, which is the point where the default admin/public account stops being the only account that matters.

Open the full guide

Part 2 of the WoowTech EMQX Complete Guide series on the Apporo blog.

Adapted from the WoowTech EMQX Complete Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.

Light · Air · Water · Control · apporo

in EMQX
Mosquitto works, right up until you want to see inside it