Deployment guide

HiveMQ Community Edition 2026.5

Overview

HiveMQ Community Edition is an open source (Apache-2.0) MQTT broker for MQTT 3.1, 3.1.1 and 5.0. Devices and applications publish messages to topics (paths such as factory/line-1/temperature) and subscribe with wildcards (factory/+/temperature, factory/#), and the broker delivers each message to every subscriber that is allowed to see it. This guide covers the HiveMQ Community Edition 2026.5 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2, which runs one HiveMQ CE broker node. It is one version of the SecureAnyCloud streaming and messaging listing on AWS Marketplace.

What you get:

  • MQTT over TLS only. Clients on the network reach the broker on 8883 (MQTT over TLS 1.3 or 1.2, modern AEAD cipher suites only). Plain MQTT on 1883 listens on 127.0.0.1 for tools on the instance and is refused from every other machine, even if a security group allows it. The upstream release starts a plain listener on 0.0.0.0:1883 instead, where usernames, passwords and every message cross the network in clear text.
  • A certificate made on your instance. At first boot the broker gets a TLS key and an end-entity certificate for this instance's own names and addresses. The certificate can only vouch for this broker and can never sign other certificates. Pin it in your clients (Step 5) or replace it with one from your CA (Step 12).
  • Logins on, with no default account. The official HiveMQ File RBAC extension 4.6.19 enforces authentication. First boot creates two logins unique to your instance: sac-admin (every topic) and sac-app (only sac/app/#). Passwords are stored only as PBKDF2-SHA512 hashes (210000 iterations, a random salt per user) in the extension's credentials.xml. The plaintext is in a root-only file for you. sudo hivemq-user adds scoped users, and no password is ever placed on a command line.
  • A broker that refuses to run without the auth extension. The HiveMQ release bundles an "allow all" extension that admits everyone, and it is not on this image. Before every start, a configuration gate refuses an unsafe change. After every start, an auth guard proves the File RBAC extension is the one answering logins, or stops the broker. A watchdog stops a running broker if the extension is disabled or another extension appears (Step 9).
  • No telemetry, no JMX. HiveMQ's anonymous usage statistics are switched off. The broker starts with a fixed command line: no remote JMX (the vendor start script opens unauthenticated JMX on port 9010), no Java agents and no heap dumps.
  • Fail closed and sandboxed. The broker runs as an unprivileged user in a systemd sandbox with no capabilities, a read-only system, a seccomp filter and no access to the instance metadata service (Step 10).
  • A pinned supply chain. HiveMQ CE 2026.5 and the File RBAC extension 4.6.19 come from their official GitHub releases, each checked against its published SHA-256, and every installed file is listed in a SHA-256 manifest. Java is OpenJDK 21 from Ubuntu. Ubuntu 24.04 LTS is fully patched at build time with unattended security upgrades on, and SSH accepts keys only.

On the image: HiveMQ Community Edition 2026.5 in /opt/hivemq/hivemq-ce-2026.5, the HiveMQ File RBAC extension 4.6.19 in /opt/hivemq/extensions/hivemq-file-rbac-extension, OpenJDK 21 (headless), the SecureAnyCloud helpers hivemq-user, hivemq-probe, hivemq-selfcheck, hivemq-set-hostname and hivemq-install-cert, cloud-init and the AWS Systems Manager agent. No compiler toolchain and no MQTT client package are installed.

  • Default user: ubuntu
  • Architecture: x86_64
  • Recommended instance type: m5.large

Prerequisites

You need:

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
  • A security group that allows TCP 22 (SSH) from your admin network and TCP 8883 (MQTT over TLS) from the networks your devices and applications connect from.

Nothing else needs to be open. Plain MQTT (1883) listens on the loopback address only, and there is no web console.

1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick HiveMQ Community Edition 2026.5 on Ubuntu 24.04 as the software version and select your Region. Choose Launch through EC2.

Select m5.large (or larger for many connections or high message rates), your key pair and a security group as above.

To launch with the AWS CLI instead, replace the values in angle brackets:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hivemq-broker}]'

The image requires IMDSv2 (session tokens). First boot takes about a minute after the instance is running. The boot service creates the logins, the certificate and the keystore, then the broker starts and the auth guard checks it.

2

Connect to your instance

Connect over SSH as the ubuntu user, the SSH user for HiveMQ Community Edition 2026.5 on Ubuntu 24.04:

ssh -i <your-key.pem> ubuntu@<public-ip>

The login banner summarises where everything is.

3

Check the services and the listening set

Check that every service is active and list the listening ports:

systemctl is-active hivemq-metadata-names hivemq-firstboot hivemq hivemq-auth-watch.timer hivemq-auth-watch.path
sudo ss -tlnp | grep -E ':(22|1883|8883) '
sudo ss -ulnp | grep java || echo 'no UDP socket'
active active active active active LISTEN 0 128 127.0.0.1:1883 0.0.0.0:* users:(("java",pid=1095,fd=1172)) LISTEN 0 128 0.0.0.0:8883 0.0.0.0:* users:(("java",pid=1095,fd=1173)) LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1142,fd=3),("systemd",pid=1,fd=60)) LISTEN 0 4096 [::]:22 [::]:* users:(("sshd",pid=1142,fd=4),("systemd",pid=1,fd=61)) no UDP socket

Each unit has one job:

  • hivemq-metadata-names reads this instance's EC2 names for the certificate.
  • hivemq-firstboot prepares the logins, certificate and keystore.
  • hivemq is the broker. It serves MQTT over TLS on 8883 for everyone, and plain MQTT on 127.0.0.1:1883 for this instance only.
  • The hivemq-auth-watch timer and path units are the watchdog from Step 9.
4

Your endpoint and logins

Everything generated for your instance is in /root/hivemq-credentials.txt, readable by root only. View the whole file with sudo cat /root/hivemq-credentials.txt. The non-secret lines are:

sudo grep -E '^HIVEMQ_(HOST|ENDPOINT|TLS_PORT|ADMIN_USER|APP_USER|APP_TOPIC_PREFIX|TLS_CERT_SHA256|TLS_PUBKEY_SHA256)=' /root/hivemq-credentials.txt
HIVEMQ_HOST=3.93.190.67 HIVEMQ_ENDPOINT=mqtts://3.93.190.67:8883 HIVEMQ_TLS_PORT=8883 HIVEMQ_ADMIN_USER=sac-admin HIVEMQ_APP_USER=sac-app HIVEMQ_APP_TOPIC_PREFIX=sac/app HIVEMQ_TLS_CERT_SHA256=AF:79:50:E0:52:CE:5A:D5:D0:47:B7:85:F0:CA:81:AF:55:58:5B:78:D0:BA:32:35:EE:65:D3:CF:DA:BE:5C:33 HIVEMQ_TLS_PUBKEY_SHA256=56af4475308785bcf15d24e8b78f09299a8b5fa7b172aeb35eae5296d6334b0f

The file also holds HIVEMQ_ADMIN_PASSWORD and HIVEMQ_APP_PASSWORD. Give devices and applications the sac-app login or a scoped user (Step 8), never the administrator's.

5

Check the certificate and pin it in your client

The broker's certificate is self-signed and made on your instance:

sudo openssl x509 -in /etc/hivemq/tls/hivemq.crt -noout -subject -fingerprint -sha256 -ext subjectAltName,basicConstraints openssl s_client -connect 127.0.0.1:8883 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256
subject=CN = hivemq-broker, O = sac sha256 Fingerprint=AF:79:50:E0:52:CE:5A:D5:D0:47:B7:85:F0:CA:81:AF:55:58:5B:78:D0:BA:32:35:EE:65:D3:CF:DA:BE:5C:33 X509v3 Subject Alternative Name: IP Address:3.93.190.67, DNS:ec2-3-93-190-67.compute-1.amazonaws.com, IP Address:172.31.86.206, DNS:ip-172-31-86-206.ec2.internal, IP Address:127.0.0.1, DNS:localhost X509v3 Basic Constraints: critical CA:FALSE sha256 Fingerprint=AF:79:50:E0:52:CE:5A:D5:D0:47:B7:85:F0:CA:81:AF:55:58:5B:78:D0:BA:32:35:EE:65:D3:CF:DA:BE:5C:33

On each client machine, copy the certificate. Before you trust it, compare what the broker serves with HIVEMQ_TLS_CERT_SHA256:

ssh -i <your-key.pem> ubuntu@<public-ip>
sudo cat /etc/hivemq/tls/hivemq.crt > hivemq.crt openssl s_client -connect <public-ip>:8883 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256
sha256 Fingerprint=AF:79:50:E0:52:CE:5A:D5:D0:47:B7:85:F0:CA:81:AF:55:58:5B:78:D0:BA:32:35:EE:65:D3:CF:DA:BE:5C:33

Then pin it for this broker only. Give hivemq.crt to the client as its CA file for this connection: --cafile for mosquitto, ca_certs for Paho, ca for MQTT.js, or a truststore of your own for a Java client. Do not add the certificate to your operating system's or browser's trust store.

A client without the pin is refused because the TLS handshake fails. The client also checks that the broker's name or address is one of the certificate's names.

When the instance's names change, the boot service re-issues the certificate for the new names on the same key. This happens, for example, when an EC2 stop and start without an Elastic IP gives a new public address. HIVEMQ_TLS_PUBKEY_SHA256 stays the same but the certificate file changes, so copy hivemq.crt to your clients again, because OpenSSL-based clients pin the exact file. An Elastic IP or your own DNS name (Step 12) avoids this.

6

Test on the instance

hivemq-probe is a small MQTT client installed for tests on the instance. It reads logins from files only and prints the broker's exact reason codes:

sudo hivemq-probe roundtrip --creds /root/hivemq-credentials.txt --identity app --topic sac/app/demo
sudo hivemq-probe connect
sudo hivemq-probe publish --creds /root/hivemq-credentials.txt --identity app --topic factory/line-1/temp
CONNACK 0x00 success CONNACK 0x00 success PUBACK 0x00 success ROUNDTRIP OK CONNACK 0x86 bad-user-name-or-password CONNACK 0x00 success PUBACK 0x87 not-authorized

The round trip publishes and receives a message as sac-app over TLS. A connection without a login is refused (0x86), and sac-app may not publish outside sac/app/# (0x87).

7

Connect a client from another machine

On the client machine, keep the certificate from Step 5 next to a file that holds the application password. Use mode 0600, and never put the password on a command line:

mkdir -p ~/hivemq && chmod 700 ~/hivemq && cd ~/hivemq ssh -i <your-key.pem> ubuntu@<public-ip>
sudo cat /etc/hivemq/tls/hivemq.crt > hivemq.crt ( umask 077; ssh -i <your-key.pem> ubuntu@<public-ip> "sudo sed -n 's/^HIVEMQ_APP_PASSWORD=//p' /root/hivemq-credentials.txt" > app.password )

mosquitto clients (mosquitto_pub / mosquitto_sub, 2.0) read default options from ~/.config/mosquitto_pub and ~/.config/mosquitto_sub. Put the login there instead of on the command line:

mkdir -p ~/.config && chmod 700 ~/.config ( umask 077; printf -- '-u sac-app\n-P %s\n' "$(cat ~/hivemq/app.password)" > ~/.config/mosquitto_sub ) cp -p ~/.config/mosquitto_sub ~/.config/mosquitto_pub mosquitto_sub -h <public-ip> -p 8883 --cafile ~/hivemq/hivemq.crt -V mqttv5 -t 'sac/app/#' -v & mosquitto_pub -h <public-ip> -p 8883 --cafile ~/hivemq/hivemq.crt -V mqttv5 -q 1 -t sac/app/sensors/temp -m 21.5
sac/app/sensors/temp 21.5

For Python with Paho MQTT 2.x (python3 -m venv paho-env && paho-env/bin/pip install paho-mqtt==2.1.0), save this as paho_demo.py:

# paho_demo.py - publish and subscribe through your sac HiveMQ broker over TLS (Paho MQTT 2.x).
# Usage:
python3 paho_demo.py <broker-host> <hivemq.crt> <user> <password-file>
# The password is read from a file, never from the command line; the broker certificate is pinned with ca_certs. import ssl, sys, threading import paho.mqtt.client as mqtt host, cafile, user, pwfile = sys.argv[1:5] password = open(pwfile).read().strip() got = threading.Event() def on_connect(client, userdata, flags, reason_code, properties): if reason_code.is_failure: print("connect refused:", reason_code) got.set() return client.subscribe("sac/app/#", qos=1) def on_subscribe(client, userdata, mid, reason_codes, properties): client.publish("sac/app/paho", "hello from paho", qos=1) def on_message(client, userdata, msg): print("received", msg.topic, "=", msg.payload.decode()) got.set() c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, protocol=mqtt.MQTTv5) c.username_pw_set(user, password) c.tls_set(ca_certs=cafile, tls_version=ssl.PROTOCOL_TLS_CLIENT) c.on_connect, c.on_subscribe, c.on_message = on_connect, on_subscribe, on_message c.connect(host, 8883) c.loop_start() got.wait(15) c.loop_stop() c.disconnect()
paho-env/bin/python paho_demo.py <public-ip> ~/hivemq/hivemq.crt sac-app ~/hivemq/app.password
received sac/app/paho = hello from paho

For Node.js with MQTT.js 5 (npm install mqtt@5), save this as mqtt_demo.js:

// mqtt_demo.js - publish and subscribe through your sac HiveMQ broker over TLS (MQTT.js 5). // Usage: node mqtt_demo.js <broker-host> <hivemq.crt> <user> <password-file> // The password is read from a file, never from the command line; the broker certificate is pinned with `ca`. const fs = require('fs'); const mqtt = require('mqtt'); const [host, cafile, user, pwfile] = process.argv.slice(2); const client = mqtt.connect(`mqtts://${host}:8883`, { ca: fs.readFileSync(cafile), username: user, password: fs.readFileSync(pwfile, 'utf8').trim(), protocolVersion: 5, }); client.on('connect', () => { client.subscribe('sac/app/#', { qos: 1 }, () => client.publish('sac/app/js', 'hello from mqtt.js', { qos: 1 })); }); const timer = setTimeout(() => { console.log('timeout'); process.exit(1); }, 15000); client.on('message', (topic, payload) => { console.log(`received ${topic}: ${payload.toString()}`); clearTimeout(timer); client.end(); }); client.on('error', (err) => { console.log(`error: ${err.message}`); clearTimeout(timer); client.end(); });
node mqtt_demo.js <public-ip> ~/hivemq/hivemq.crt sac-app ~/hivemq/app.password
received sac/app/js: hello from mqtt.js

The broker refuses four kinds of connection, shown here from the client machine as mosquitto output: no login, a topic outside the login's role, plain MQTT on 1883, and TLS without the pinned certificate:

Connection error: Bad User Name or Password Warning: Publish 1 failed: Not authorized. Error: Connection refused Error: Protocol error

The MQTT reason codes behind them are 0x86 (no or unknown login) and 0x87 (wrong password, or a topic the login's role does not grant, shown as PUBACK/SUBACK 0x87). For MQTT 3.1.1 clients, the CONNACK codes are 4 and 5.

8

Topics, roles and scoped users

Each login has one role, and each role lists the topic filters it may publish and subscribe to:

sudo hivemq-user list
sac-admin sac-admin
# sac-app sac-app sac/app/#

Add a user for one device or one application, with its own topic prefix. The command generates the password on the instance and writes it only to /root/hivemq-user-<name>.txt (mode 0600). To use your own password instead, pass --password-stdin, which reads one of 16 characters or more from standard input:

sudo hivemq-user add sensor-17 factory/line-1
sudo hivemq-user list
hivemq-user: added sensor-17 (topics factory/line-1/#); its password is in /root/hivemq-user-sensor-17.txt sac-admin sac-admin
# sac-app sac-app sac/app/# sensor-17 scoped-sensor-17 factory/line-1/#

sensor-17 may now publish and subscribe on factory/line-1/# and nothing else. The broker reloads the users within ten seconds, and the helper waits until the new login works. Other commands:

  • sudo hivemq-user passwd <name> gives a user a new password. For sac-admin and sac-app it also updates /root/hivemq-credentials.txt.
  • sudo hivemq-user remove <name> removes a scoped user and its role.
  • sudo hivemq-user hash reads a password on standard input and prints its hash string, for when you edit credentials.xml by hand. The file is /opt/hivemq/extensions/hivemq-file-rbac-extension/conf/credentials.xml (root:hivemq 0640), and the format is the extension's own salt:iterations:hash.

hivemq-user refuses --password, so passwords never appear in the process list or in logs. Keep the sac-admin login, because the auth guard uses it to prove the broker is serving your users.

9

The broker never runs without its auth extension

HiveMQ CE has no built-in user database, so authentication comes from an extension. If that extension failed to load while an "allow all" extension was present, the broker would admit anyone. Three checks make sure that cannot happen:

  • hivemq-config-gate runs before every start and refuses to start the broker unless all of the following hold: the listeners are exactly TLS on 0.0.0.0:8883 and plain MQTT on 127.0.0.1:1883; usage statistics are off; the extensions folder holds only the File RBAC extension 4.6.19 (no DISABLED marker, no other extension, no legacy credential file); its configuration is unchanged (hashed passwords, a failed login is final); and credentials.xml parses, keeps sac-admin and holds only strong hashes.
  • hivemq-auth-guard runs right after every start. It checks HiveMQ's log for the File RBAC extension start, the exact listening set, that a login-less client is refused on both listeners, that a wrong password is refused and that sac-admin is accepted. If anything is off, it stops the broker, so no listener is left open.
  • hivemq-auth-watch repeats those checks every minute and whenever anything changes in the extensions folders, and stops a running broker if the extension is disabled or another extension appears.
sudo journalctl -u hivemq -o cat --no-pager | grep -E 'hivemq-config-gate|hivemq-auth-guard|Extension "'
hivemq-config-gate: OK (TLS-only 0.0.0.0:8883 + 127.0.0.1:1883, File RBAC 4.6.19 alone, 20 environment names checked) INFO - Extension "HiveMQ File Role Based Access Control Extension" version 4.6.19 started successfully. hivemq-auth-guard: OK (start): File RBAC 4.6.19 is the only extension; anonymous 0x86 x2, wrong password 0x87, sac-admin 0x00 x2

If the broker does not start after you change something, journalctl -u hivemq shows the reason on a REFUSED: line. Undo the change and run sudo systemctl start hivemq. If the watchdog stopped the broker, journalctl -u hivemq-auth-watch shows why.

10

Why plain MQTT 1883 is closed, and the other defaults

  • 1883 is loopback only. MQTT without TLS sends the username, the password and every message in clear text. The broker therefore listens for plain MQTT on 127.0.0.1:1883 only. This is handy for scripts on the instance, which still need a login. The configuration gate refuses to start the broker with 1883 on any other address. Use mqtts://<host>:8883 from every other machine.
  • Instance metadata is blocked. The broker, the boot service and the watchdog cannot reach the EC2 instance metadata service (169.254.169.254) or its IPv6 address. A small separate unit reads only this instance's names for the certificate. A compromised broker therefore cannot use the instance's role credentials.
systemctl show -p IPAddressDeny hivemq
IPAddressDeny=::ffff:169.254.169.254/128 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 ::ffff:168.63.129.16/128
  • No telemetry. HiveMQ's anonymous usage statistics are disabled in /etc/hivemq/config.xml (<anonymous-usage-statistics><enabled>false</enabled>). The gate refuses to start the broker if they are switched on, so the broker sends nothing to HiveMQ.
  • No JMX, no heap dumps. The broker runs from a fixed java command line, and the gate refuses a changed one, for example one that adds JMX. Logs go to the journal only (journalctl -u hivemq) and never contain a password: a failed login is logged as Authentication failed because of invalid credentials.
11

Check everything at once

Run the combined self-check:

sudo hivemq-selfcheck
ok: units active: hivemq-metadata-names, hivemq-firstboot, hivemq, hivemq-auth-watch (timer + path) ok: OK (watch): File RBAC 4.6.19 is the only extension; anonymous 0x86 x2, wrong password 0x87, sac-admin 0x00 x2 ok: extensions folder: hivemq-file-rbac-extension only (no allow-all, no DISABLED marker) ok: listening set: 0.0.0.0:8883 (TLS) and 127.0.0.1:1883 (this instance only); no UDP ok: certificate served on 8883 = /etc/hivemq/tls/hivemq.crt = credentials file (SHA-256 AF:79:50:E0:52:CE:5A:D5...); end-entity; covers 172.31.86.206 127.0.0.1 (endpoint 3.93.190.67) ok: TLS publish/subscribe round trips: sac-admin and sac-app via 127.0.0.1 and 172.31.86.206 ok: refusals: anonymous 0x86 (TLS + local), wrong passwords 0x87 (both logins), plain MQTT 1883 not reachable on 172.31.86.206, plain MQTT on 8883 gets no CONNACK ok: RBAC: sac-app refused outside sac/app/# (PUBACK 0x87, SUBACK 0x87) and nothing was delivered to the administrator ok: instance metadata blocked inside the broker's cgroup (000) while loopback is open ok: telemetry: anonymous usage statistics disabled and never started; no JMX, no agent, no heap dumps SELFCHECK OK
12

Use your own DNS name or a certificate from your CA

To give clients a stable name, point a DNS record (or an Elastic IP) at the instance and tell the broker about it. The command re-issues the certificate on the same key to cover the name, and the broker restarts:

sudo hivemq-set-hostname mqtt.example.com

To serve a certificate issued by your own CA (or a public one), install the chain (server certificate first) and its unencrypted PEM key. The boot-time renewal never replaces it, and clients then trust your CA instead of pinning this instance's certificate:

sudo hivemq-install-cert /path/to/fullchain.pem /path/to/privkey.pem mqtt.example.com

To go back to a new self-signed certificate, run sudo hivemq-set-hostname <name>. These helpers rebuild the keystore and its password (/etc/hivemq/tls/keystore.env, root only). Never pass the keystore password on a command line.

Logs, files and limits

  • Logs: journalctl -u hivemq (the broker, the gate and the guard), journalctl -u hivemq-firstboot and journalctl -u hivemq-auth-watch. Client connect and disconnect events are logged with the client id, address and reason.
  • Files: broker configuration /etc/hivemq/config.xml (root:hivemq 0640), logging /etc/hivemq/logback.xml, TLS material /etc/hivemq/tls/, users and roles in the RBAC extension's conf/credentials.xml, and persistent sessions and retained messages in /var/lib/hivemq.
  • Restart: sudo systemctl restart hivemq. The gate and the guard run on every start.
  • Limits: HiveMQ Community Edition is a single broker node, and clustering and the Control Center are HiveMQ Enterprise features. The Java heap is half the instance's memory, so size the instance for your connection count and message rate.

Support

SecureAnyCloud provides support for this image. Contact sales@secureanycloud.com with the instance ID and the output of sudo hivemq-selfcheck, which never prints a password.

Deploy on AWS

Launch HiveMQ Community Edition 2026.5 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS