Skip to Content

Send your first message, then decide who else may

hello, then who goes there
EMQX Guide · Part 3

Send your first message, then decide who else may

Part 2 left you with a Dashboard you can read and a publish/subscribe model that has only ever existed on paper. This part closes both gaps in one sitting. First you send a real MQTT message and watch it come back, using a client that is already inside EMQX — nothing to install and not one line of code. Then you deal with what that first message quietly exposed: until you create an authenticator, an empty username and an empty password are enough to get in, and anything that gets in can read and write your whole topic space.

8083
The port the in-browser client speaks MQTT over WebSocket on. 1883 is plain TCP, which a browser cannot open by itself
3 of 5
Tools on the Diagnose menu that exist only in the paid Enterprise edition. Do not go hunting for them in Open Source 5.8.9
No password
What it currently takes to connect to your broker. That is the hole the second half of this part closes
Running is not the same as safe

The broker works. That is a smaller claim than it sounds

EMQX 5.8.9 is installed, the Dashboard opens, and the tour in Part 2 built the mental model: a publisher sends a message on a topic, a subscriber asks for the topics it cares about, and the broker in the middle routes every message to whoever asked for it. All of that is still theory. You have not yet watched a single message travel through your own broker.

Fixing that takes one page of the Dashboard, because EMQX ships a test client inside it. And the moment you use it you will notice something the theory never mentioned: it connects with the Username and Password fields left blank, and it works.

What you will do firstOpen a client that is already there, connect on port 8083, subscribe to testtopic/#, publish to testtopic/1, and watch your own message come back to you.
What that revealsNothing asked who you were. Until an authentication resource exists, EMQX lets a client connect straight through — convenient while you are only confirming that one instance works, and a hole once anything else can reach the machine.

That second point is not a scare story bolted onto a tutorial. Anyone who can reach your 1883 or your 8083 can publish to, and read, your entire topic space. The Woow add-on documentation lists “set up MQTT authentication after your first login” as required, not optional — which is why the first message and the first password belong in the same sitting rather than in two parts a week apart.

The order matters, and it is deliberate. Connect with no credentials first, so that you have a known-good baseline: if something breaks after you add authentication, you already know the broker itself was fine. Then add the authenticator and prove it took effect by getting a wrong password rejected. Doing it the other way round leaves you debugging two things at once.
The client already inside

Diagnose → WebSocket Client, and the three menu items that are not there

There are several ways to talk to an MQTT broker. EMQX itself points at the desktop client MQTTX, the command-line MQTTX CLI and the browser build MQTTX Web. All three have to be installed, or at least remembered, somewhere outside EMQX. The fourth option does not: the WebSocket Client built into the Dashboard. It speaks MQTT over WebSocket, connects on port 8083 by default, and does all three actions — connect, subscribe and publish — right there in the page. For a first test tool that is the right trade.

You find it under Diagnose in the left menu. That menu holds five entries, and this is the part worth knowing before you go looking: three of them only exist in the paid EMQX Enterprise edition. On Open Source 5.8.9 you have two.

Entry under DiagnoseEditionWhat it is for
AlarmsEnterprise onlyNot present in your Open Source 5.8.9 Dashboard
WebSocket ClientOpen Source and EnterpriseConnect, subscribe and publish from the browser. This whole part rests on it
Topic MonitoringEnterprise onlyNot present in your Open Source 5.8.9 Dashboard
Slow SubscriptionsEnterprise onlyNot present in your Open Source 5.8.9 Dashboard
Log TraceOpen Source and EnterpriseThe other one that works here. It traces logs rather than sending messages

Hunting an Open Source interface for a menu item that was only ever in Enterprise is a rite of passage nobody enjoys. The table above is there to save you that particular afternoon.

What the page gives you

The WebSocket Client covers three stages — connect, subscribe, publish — and keeps two lists underneath: Published, what you sent, and Received, what came back. Click + to open several WebSocket connections at once, each one independent of the others. That is how you simulate two devices: one connection subscribing, another publishing.

One behavior surprises everyone exactly once. Refreshing this page clears every connection and all the sent and received data. It is a quick test tool, not a place that keeps history.

In plain terms

It is a whiteboard, not a notebook. Excellent for working something out in front of you, and wiped the moment somebody walks past with a cloth. If you want the working kept, that is a different object — the desktop MQTTX, which saves connections and history.

TermPlain EnglishIn one line
Publishsend a messageSend a message to a topic
Subscribeask for a topicDeclare which topics you want messages from
Topicmessage addressThe hierarchical name that classifies a message
Payloadmessage bodyThe data a publish actually carries
QoSdelivery guaranteeHow strongly message delivery is guaranteed (0/1/2)
Retainedlast message keptThe broker remembers the last message and a new subscriber receives it at once
WebSocketbrowser transportThe transport that lets a browser speak MQTT
Your first publish

Four moves, and a message that comes back to you

The trick that makes this test so cheap is that you are going to be both ends at once. One connection subscribes to a filter, the same connection publishes to a topic that filter covers, and the broker routes the message back across to you. If the row appears in Received, every link in the chain worked.

  1. Step 1

    Open the WebSocket client

    Log in to the EMQX Dashboard. If you changed the username and password after installing, in Part 1, use your own. In the left menu click Diagnose → WebSocket Client.

  2. Step 2

    Make the first connection

    In the Connection block, leave Host as localhost and Port as 8083. Leave Username and Password empty — no authentication is set up yet, and that is exactly the state we are about to examine. Click Connect. When the status turns to Connected, you are through.

    Host: localhost
    Port: 8083

    If you have the Dashboard open from another device rather than from the machine itself, localhost means that other device and will not connect. Put your Home Assistant host address in the Host field instead.

  3. Step 3

    Subscribe, then publish

    In the Subscription block set Topic to testtopic/# and click Subscribe. Then in the Publish block set Topic to testtopic/1, put {"msg":"Hello"} in Payload, start with QoS 0, and click Publish. The same message shows up in the Received area below, because you are the subscriber as well.

    Subscription topic: testtopic/#
    Publish topic: testtopic/1
    Payload: {"msg":"Hello"}
  4. Step 4

    Verify QoS

    Change the Publish QoS to 1, send another message, and watch it reach Received just the same. Then try 2. Nothing dramatic happens on screen — and that is worth seeing for yourself before the next section explains what the three levels actually promise.

flowchart LR
  S["Subscription block:
subscribe to testtopic/#"] --> B A["Publish block:
publish to testtopic/1"] --> B["EMQX asks: does any live
subscription filter match
the topic testtopic/1?"] B --> D["Received list, in the very
same tab, because you are
the subscriber as well"]
One tab, both endsTwo arrows enter the broker box from the left, and both of them start in the same browser tab — upper box the subscription, lower box the publish. The single arrow out is the loop closing. If nothing lands in Received, the failure is somewhere in the middle box, not in your typing.

There is one rule about that pair of topics that catches nearly everybody, and it is worth internalizing before you invent your own names. The Topic in the Publish block cannot carry the + or # wildcards. Only a Subscription topic may use them. A publish names one exact topic; a subscription describes a set.

flowchart TD
  A["The topic string you are
about to type"] --> B{"Does it contain
a + or a # ?"} B -->|"no"| C["Both blocks take it.
testtopic/1 is fine
on either side"] B -->|"yes"| D{"Which block are
you typing into?"} D -->|"Subscription"| E["Accepted. testtopic/# is
a filter, and it matches
testtopic/1"] D -->|"Publish"| F["Refused. A publish topic
names one exact topic"]
Where a wildcard is allowedThree end boxes, and only one of them is a refusal — you reach it solely by putting a wildcard in the Publish block. The plain topic on the far left, with no wildcard at all, is accepted by both blocks.
Two connections beat one. Once the single-connection loop works, click + and open a second WebSocket Client. Subscribe on one, publish from the other. It is a far more honest rehearsal of what Home Assistant and a sensor will do to each other, and it costs you one click.
QoS, and what comes back

Three delivery guarantees, and none of them is “better”

QoS — Quality of Service — is the MQTT mechanism that controls how strongly the delivery of a single message is guaranteed. EMQX supports all three levels at both ends, and in the WebSocket client you pick one for the subscription and one for the publish.

QoSNameGuaranteeTypical use
0At most onceNo guarantee of delivery, and none against duplicatesPeriodic sensor readings, where dropping one does no harm
1At least onceDelivery guaranteed, but it may arrive twiceState changes where a repeat or two is acceptable
2Exactly onceDelivery guaranteed, and never duplicatedSwitches and control commands, where a repeat is not allowed

Read that middle column again, because the shorthand people repeat — “higher is more reliable” — loses the part that actually bites. QoS 1 does not mean “more likely to arrive”; it means arrival is guaranteed and a duplicate is possible. If the thing on the other end opens a garage door, a duplicate is not a lesser problem than a loss.

In plain terms

QoS 0 is shouting a number across the kitchen while somebody is cooking. Usually heard, occasionally not, and you carry on regardless because another reading is coming in thirty seconds. QoS 1 is phoning and repeating yourself until they say yes — they definitely got it, and they may well have written it down twice. QoS 2 is the courier who needs a signature and will not leave a second parcel: it costs the most back-and-forth, and it is the only one you want for “unlock the door.”

The cheapest way to get a feel for it is the loop you already built: publish to a topic you subscribe to yourself. Because the publisher and the subscriber are the same end, the broker still routes the message across, and the Received rows let you confirm with your own eyes whether the same message comes back after a QoS change, and whether it arrives twice.

Retained is a separate switch

While you are in the Publish block, tick Retain and send one more message. The broker now remembers that message as the last one on that topic, and a new subscriber receives it immediately on subscribing instead of waiting for the next publish. Open a second connection with +, subscribe to testtopic/#, and it arrives before you have done anything else.

sequenceDiagram
  participant A as Connection A
  participant E as EMQX
  participant B as Connection B
  A->>E: publish testtopic/1, Retain ticked
  E->>E: store it as the retained message
  B->>E: subscribe to testtopic/#35;
  E->>B: hand over the retained message at once
  A->>E: publish testtopic/1 again, Retain ticked
  E->>B: deliver it as an ordinary message
Why a new subscriber gets something before anything is sentConnection B sits on the right and does nothing but subscribe. It receives exactly two arrows: the first is the retained copy EMQX kept from the publish at the top of the diagram, handed over the instant B subscribes; the second is an ordinary delivery. From B's side the two look identical.
Retained and QoS are two different things. QoS is about the delivery of one message in flight; Retain is about whether the broker keeps a copy to hand to whoever subscribes next. You can combine any QoS with Retain on or off, and the model for that was laid out in Part 2.
Turning the lock on

Password-Based, with the built-in database

Everything so far worked with the Username and Password fields empty. Now we close that. Expand Access Control in the Dashboard's left menu and you get three items: Authentication, Authorization and Banned Clients, the blocklist. This part is the first of those. The second is Part 4.

EMQX keeps the two firmly apart, and the distinction is the single most useful thing in this section. Authentication answers “who are you?” — confirmed by a username and password, a client ID, a JWT or a similar mechanism. Authorization answers “what publishes and subscribes may this identity make?”

In plain terms

It is the badge at the front desk versus the list of rooms your badge opens. Authentication is the badge: the guard is satisfied you are who you say. Authorization is the list: this badge opens the second floor and the store cupboard, and nothing else. A building with badges and no room list is a building where everyone who got through the door can walk into the server room.

TermPlain EnglishIn one line
Authenticationidentity checkConfirms who you are
Password-Basedpassword mechanismChecks a username (or client ID) plus a password
Built-in Databasebuilt-in storeEMQX keeps the users and passwords itself
CredentialcredentialsThe data that proves an identity
JWTsigned tokenA token signed by an issuer that carries claims
HTTP ServerHTTP backendYour own HTTP service returns the authentication verdict
LDAPdirectory protocolA company directory that checks a user and password

What you are choosing between

Creating an authenticator usually takes four steps: choose a Mechanism, choose a Backend that stores or fetches the data, fill in the connection details, and create it. The mechanisms are Password-Based (username and password), JWT (a token) and MQTT 5.0's SCRAM, a stronger, mutual check. The backends are the EMQX built-in database, an external database — MySQL, PostgreSQL, MongoDB or Redis — and an HTTP Server. JWT needs no backend at all.

flowchart LR
  M["Step 1
Mechanism"] --> P["Password-Based"] M --> J["JWT
(no backend to pick)"] M --> SC["SCRAM (MQTT 5.0)"] P --> B["Step 2
Backend"] B --> B1["Built-in Database"] B --> B2["MySQL / PostgreSQL /
MongoDB / Redis"] B --> B3["HTTP Server"]
Mechanism first, backend secondOnly the Password-Based box carries on into a second column; the JWT and SCRAM boxes end where they are, because JWT verifies a signature itself and SCRAM is a different conversation altogether. The three boxes down the right-hand side are the whole backend choice.

For a home add-on install the practical choice is Password-Based plus Built-in Database. There is no second database to maintain, and adding a user directly in the Dashboard is enough to let Home Assistant and Zigbee2MQTT connect with a username and password. That is the route the steps below take.

  1. Step 1

    Open the Authentication page

    In the Dashboard's left menu go to Access Control → Authentication, then click Create at the top right.

  2. Step 2

    Create Password-Based plus the built-in database

    On the Create page pick Password-Based as the mechanism and Built-in Database as the backend. Set whether it matches on Username or ClientID, and which password hash to use, to suit your case. Then click Create. External databases and HTTP Server are left to the concept section below; you do not need them here.

  3. Step 3

    Add a user

    Find the authenticator you just created in the Authenticator List, click User Management, and add a username and a password — for example ha_broker with a password of your own choosing. It is stored in the EMQX built-in database. Write the password down somewhere you will still have it when you point Home Assistant at the broker.

  4. Step 4

    Prove it took effect, then put it back

    Go back to the WebSocket client from earlier in this part and connect with the credentials you just created — then try again with a deliberately wrong password and watch it be rejected. That rejection is the proof; a successful connection on its own does not tell you the authenticator is doing anything. If you also want to see what disabling does, turn this authenticator's Enable switch off in the Authenticator List, watch every client connect again, and turn it straight back on when the experiment is over. Delete any user you no longer need from User Management.

Two settings that will bite you later

The built-in database is the backend with the least to look after: usernames and passwords live in EMQX's own database and there is no separate data service to run. You can add and delete accounts by hand in User Management, or download the official template, fill it in, and use Import to create many at once. Two details on that page deserve more attention than they get.

The first is UserID Type: whether an account is identified by its username or by its client ID when it connects. It has to match the field your client actually sends: register an account by username, and a client that identifies itself only by client ID gives the check nothing to compare.

The second is a one-way door. Once you change Password Hash or Salt Position, every credential already created stops working, and you have to create the users again. Decide the hash before you add twenty devices, not after — and if you do change it, plan on re-entering every account and re-pointing every client at the new password in the same maintenance window.

What the Enable switch really does

Each authenticator in the list has an Enable switch. The official documentation is explicit about what happens when you turn it off: after that, “all clients can connect.” It does not shut everyone out. It takes this identity check away.

In plain terms

It is sending the receptionist home for the evening. Nobody is turned away at the desk, because nobody is asked. If you switched it off for a maintenance job, the building is open until you switch it back on — and it looks exactly the same from the outside either way, which is what makes this one easy to leave off by accident.

flowchart TD
  A["A client sends CONNECT"] --> B{"Is an authenticator there,
with Enable switched on?"} B -->|"no authenticator, or Enable off"| C["Connected.
Every client is let in"] B -->|"yes"| D{"Do the credentials match
the built-in database?"} D -->|"no"| E["Rejected"] D -->|"yes"| F["Connected as that identity"] C --> G["Free to publish and subscribe
anywhere in the topic space,
until authorization is added"] F --> G
What happens at connect timeRejected is the only dead end on the page. Both boxes that say Connected — the anonymous one on the far left and the authenticated one on the right — feed into the same bottom box, which is the honest picture: a password decides whether you get in, and nothing yet decides what you may do once you are.

That bottom box is Part 4's job, and it is why finishing this part does not mean you are finished. Authentication is the half that has to come first, because there is nothing to write rules about until identities exist.

JWT, HTTP and LDAP

The three you should recognize, and probably not build today

The Create page offers more than the route you just took. You do not need any of it for a home install, but you should be able to recognize each one and know when it earns its place — otherwise you will either reach for the wrong one or spend an evening looking for one that is not in your edition.

JWT

JWT (JSON Web Token) is token-based authentication. The client puts a JWT token into the username or password field when it connects, and EMQX only has to check the signature and the claims in the Payload — which is why JWT needs no backend of its own. When you create it you choose Secret (verify with a shared key) or Public Key (verify with a public key), say whether the secret is Base64-encoded, and fill the claims you want checked into Payload.

If you use a JWKS Endpoint, EMQX periodically fetches a set of RSA or ECDSA public keys from the authorization server to verify the JWT, and you set the refresh interval in seconds. JWT fits the case where an existing identity service already issues the tokens and you only want EMQX to accept them too. For a plain self-hosted Home Assistant setup that is usually a bonus rather than a requirement: with no token-issuing service in the picture, a username and password is simpler.

HTTP Server

HTTP Server hands authentication to an external HTTP service that you provide yourself. EMQX sends every connection request to that URL and allows or denies it according to the response. You configure the request method (POST or GET), the request URL — which must include the http or https scheme — the headers, and the data to be checked in the body, usually username and password. It can sit on top of an account system you already have, but you have to maintain that service and make sure the response format is what EMQX expects. A broker whose authentication depends on a second service you wrote is a broker with a second thing that can fail at three in the morning.

LDAP

LDAP (Lightweight Directory Access Protocol) is the protocol for checking a user against a directory server. The important part first: in EMQX, LDAP is only available in the paid Enterprise edition, so you will not find it in your Open Source 5.8.9 Dashboard. Conceptually it borrows an existing LDAP directory as the source of accounts. If reusing an account directory you already run is the goal, your options under Open Source are the built-in database, or an HTTP Server fronting your existing identity service.

RouteWhat you have to run yourselfEditionWhen it earns its place
Password-Based + Built-in DatabaseNothing beyond EMQXOpen Source and EnterpriseA home add-on install. Start here
Password-Based + external databaseMySQL, PostgreSQL, MongoDB or RedisOpen Source and EnterpriseA large number of accounts, central management, or an identity system you already run
Password-Based + HTTP ServerYour own HTTP service, and its response formatOpen Source and EnterpriseYou want the verdict to come from an account system you already have
JWTWhatever issues and signs the tokensOpen Source and EnterpriseTokens are already being issued somewhere and you want EMQX to accept them too
LDAPA directory serverEnterprise onlyNot an option on Open Source 5.8.9, whatever your directory looks like
A reasonable stopping point. If you set up Password-Based with the built-in database, added one account for Home Assistant and one for anything else that connects, and confirmed a wrong password is refused, you have done what this part asks. Everything above is context for the day your setup outgrows it.
When it does not work

The failures that actually happen, in the order they happen

SymptomLikely causeHow to fix it
Connect does nothing, or keeps failing Another service — WebRTC, for example — has taken 8083, the same kind of port conflict covered when you installed the add-on. Or you are coming in from another device Check what else is holding 8083. If you are connecting from another device, Host has to be the Home Assistant host address, not localhost
You subscribed but nothing arrives The subscription topic does not cover the publish topic Check that the filter matches with its wildcard — only a subscription to testtopic/# matches testtopic/1. After a successful publish the Received area should hold a row; if there is not a single one, the broker did not actually route the message
The same message arrives more than once You are on QoS 1, which guarantees at-least-once delivery A duplicate is possible by design, and it is not a broker fault. Choose QoS 2 when you need exactly one copy
Everything disappears after you refresh the page The built-in WebSocket client clears itself by default Not a bug. If you need connection history or several saved setups, switch to the desktop MQTTX; that is what suits ongoing testing
Home Assistant stops connecting once you create an authenticator The field you matched on, or the password, is wrong Check whether UserID Type reads the username or the client ID, the case of the account name you added, and its password. Check the authenticator has not been left disabled — if your experiment turned Enable off, switching it back on restores things
After you turn Enable off, every client can connect That is by design. Disabling takes the whole authentication layer away It does not tighten anything, so do not read a disabled authenticator as protection switched on. To keep out clients you do not recognize you need authorization alongside a working authenticator
JWT keeps failing authentication A mismatch between how the token was signed and how EMQX was told to verify it Check whether you chose Secret or Public Key, whether the Base64 switch matches on both sides, and whether the Payload claims match the claims inside your JWT. Start with a token you can read on the issuing side and test it in the Dashboard by the shortest path
The external database or HTTP backend shows Disconnected EMQX cannot reach that server, or the query failed Check the server address, the port, the credentials and whether the response format is what EMQX expects. Once the external side is fixed, go back to the Authenticator List and let it connect again
How does the built-in WebSocket client differ from MQTTX?
The built-in client lives inside the EMQX Dashboard, needs no install, and is the fastest way to glance at messages. MQTTX — desktop, CLI and web — does more: it saves several connections and supports finer MQTT 5.0 settings, which suits ongoing debugging and development. Both talk to the broker the same way, so there is no rule that you must use one of them.
Why does the test use 8083 rather than 1883?
The built-in client is the channel where the browser runs MQTT over WebSocket right in the page, and that goes over 8083. 1883 is plain TCP MQTT, which a browser cannot open directly; to reach 1883 you need a tool such as the desktop MQTTX or the CLI. Both are MQTT — only the transport layer differs.
Which of QoS 0, 1 and 2 should I actually choose?
Pick 0 for data you can afford to drop, 1 for data that must go out but may repeat, and 2 for critical control that must not repeat, such as a switch. Publish once at each of the three first, look at the difference in what you receive on the same connection, then choose by your real situation.
Can the tool hold several connections at once?
Yes. Click + to open several WebSocket Clients at the same time, each with its own connection state and its own sent and received rows. If you want to simulate one publisher and one subscriber, it is easier to open two connections and use one for subscribing and the other for publishing.
Aren't authentication and authorization the same thing?
No. Authentication confirms who you are; authorization decides what you may do on which topics. A username and password only completes the first half: with no authorization rules, a client that can log in is still free to publish and subscribe on every topic. Authorization is how you close that door to the minimum, and it is the first half of Part 4.
Which suits home use, the built-in database or MySQL/Redis?
For a home add-on install the built-in database is already enough, and it saves you maintaining a second database. An external database suits a large number of accounts, central management, or an identity system you already run. If you want a clean setup with one less thing to fail, choose the built-in one.
Where does JWT fit in a smart home?
If some token-issuing service already hands out all your tokens and you want EMQX to accept them too, JWT is the natural answer. For a self-hosted Home Assistant where you just want HA and Zigbee to connect, a username and password is usually more obvious; leave JWT until you really need central tokens.
Why can't I find LDAP?
Because the LDAP authentication backend is only in the EMQX Enterprise edition, and Open Source 5.8.9 does not have it. If you want to reuse an account directory you already run, your options under Open Source are the built-in database, or an HTTP Server that fronts your existing identity service.
Next

Where to go from here

half the door

Your broker now knows who is knocking. It still does not care what they do.

A message has travelled through your own EMQX and come back, and a wrong password is refused. Part 4 takes the other half: authorization, which decides which topics an identity may publish to and subscribe to, and then listeners and TLS — the ports themselves, and how to stop the password you just set from crossing the network in the clear.

Open the full guide

Part 3 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
The Dashboard in front of you, and the five words underneath it