HiveMQ Community Edition 2026.5 on AWS User Guide
Overview
This guide covers launching and using the HiveMQ Community Edition 2026.5 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg streaming and messaging listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
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/#); the broker delivers each message to every subscriber that is allowed to see it. This image runs one HiveMQ CE broker node.
What the cloudimg image adds:
- 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.1for 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 on0.0.0.0:1883, 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. It can only vouch for this broker and can never sign other certificates. You pin it in your clients (Step 5) or replace it with one from your CA (Step 12).
- Logins that are on, with no default account. Authentication is enforced by the official HiveMQ File RBAC extension 4.6.19. First boot creates two logins unique to your instance:
cloudimg-admin(every topic) andcloudimg-app(onlycloudimg/app/#). Their passwords are stored only as PBKDF2-SHA512 hashes (210000 iterations, a random salt per user) in the extension'scredentials.xml; the plaintext is in a root-only file for you.sudo hivemq-useradds scoped users. 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; it is not on this image. Before every start a configuration gate refuses an unsafe change, and 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 is started with a fixed command line: no remote JMX (the vendor start script opens unauthenticated JMX on port 9010), no Java agents, 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.
What is 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 cloudimg 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
- 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.
Step 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 your Region, then Launch through EC2. Choose m5.large (or larger for many connections or high message rates), your key pair and a security group as above.
With the AWS CLI (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.
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| HiveMQ Community Edition 2026.5 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
The login banner summarises where everything is.
Step 3: Check the services and the listening set
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
hivemq-metadata-names reads this instance's EC2 names for the certificate, hivemq-firstboot prepares the logins, certificate and keystore, hivemq is the broker (MQTT over TLS on 8883 for everyone, plain MQTT on 127.0.0.1:1883 for this instance only), and the hivemq-auth-watch timer and path units are the watchdog from Step 9.
Step 4: Your endpoint and logins
Everything generated for your instance is in /root/hivemq-credentials.txt (readable by root only). View it all 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=cloudimg-admin
HIVEMQ_APP_USER=cloudimg-app
HIVEMQ_APP_TOPIC_PREFIX=cloudimg/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 cloudimg-app login or a scoped user (Step 8), not the administrator's.
Step 5: Check the certificate and pin it in your client
The broker's certificate is self-signed, 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 = cloudimg
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 and compare what the broker serves with HIVEMQ_TLS_CERT_SHA256 before you trust it:
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, 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 (the TLS handshake fails), and the broker's name or address must be one of the certificate's names (the client checks it).
When the instance's names change (an EC2 stop and start without an Elastic IP gives a new public address), the boot service re-issues the certificate for the new names on the same key: HIVEMQ_TLS_PUBKEY_SHA256 stays the same but the certificate file changes, so copy hivemq.crt to your clients again (OpenSSL-based clients pin the exact file). An Elastic IP or your own DNS name (Step 12) avoids this.
Step 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 cloudimg/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 cloudimg-app over TLS; a connection without a login is refused (0x86), and cloudimg-app may not publish outside cloudimg/app/# (0x87).
Step 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 (mode 0600; the password never goes 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): they read default options from ~/.config/mosquitto_pub and ~/.config/mosquitto_sub, so the login goes there instead of on the command line:
mkdir -p ~/.config && chmod 700 ~/.config
( umask 077; printf -- '-u cloudimg-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 'cloudimg/app/#' -v &
mosquitto_pub -h <public-ip> -p 8883 --cafile ~/hivemq/hivemq.crt -V mqttv5 -q 1 -t cloudimg/app/sensors/temp -m 21.5
cloudimg/app/sensors/temp 21.5
Python with Paho MQTT 2.x (python3 -m venv paho-env && paho-env/bin/pip install paho-mqtt==2.1.0), saved as paho_demo.py:
# paho_demo.py - publish and subscribe through your cloudimg 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("cloudimg/app/#", qos=1)
def on_subscribe(client, userdata, mid, reason_codes, properties):
client.publish("cloudimg/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 cloudimg-app ~/hivemq/app.password
received cloudimg/app/paho = hello from paho
Node.js with MQTT.js 5 (npm install mqtt@5), saved as mqtt_demo.js:
// mqtt_demo.js - publish and subscribe through your cloudimg 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('cloudimg/app/#', { qos: 1 }, () => client.publish('cloudimg/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 cloudimg-app ~/hivemq/app.password
received cloudimg/app/js: hello from mqtt.js
What the broker refuses, as seen from the client machine (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), 0x87 (wrong password, or a topic the login's role does not grant: PUBACK/SUBACK 0x87). For MQTT 3.1.1 clients the CONNACK codes are 4 and 5.
Step 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
cloudimg-admin cloudimg-admin #
cloudimg-app cloudimg-app cloudimg/app/#
Add a user for one device or one application with its own topic prefix. The password is generated on the instance and written only to /root/hivemq-user-<name>.txt (0600); --password-stdin reads one of your own (16 characters or more) from standard input instead:
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
cloudimg-admin cloudimg-admin #
cloudimg-app cloudimg-app cloudimg/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; the helper waits until the new login works. Other commands:
sudo hivemq-user passwd <name>gives a user a new password (forcloudimg-adminandcloudimg-appit also updates/root/hivemq-credentials.txt).sudo hivemq-user remove <name>removes a scoped user and its role.sudo hivemq-user hashreads a password on standard input and prints its hash string, if you editcredentials.xmlby hand (/opt/hivemq/extensions/hivemq-file-rbac-extension/conf/credentials.xml, root:hivemq 0640; the format is the extension's ownsalt:iterations:hash).
Passwords are never accepted on the command line (hivemq-user refuses --password), so they never appear in the process list or in logs. Keep the cloudimg-admin login: the auth guard uses it to prove the broker is serving your users.
Step 9: The broker never runs without its auth extension
HiveMQ CE has no built-in user database: authentication comes from an extension. If that extension failed to load and an "allow all" extension were present, the broker would admit anyone. Three checks make sure that cannot happen:
hivemq-config-gateruns before every start and refuses to start the broker unless the listeners are exactly TLS on0.0.0.0:8883and plain MQTT on127.0.0.1:1883, usage statistics are off, the extensions folder holds only the File RBAC extension 4.6.19 (noDISABLEDmarker, no other extension, no legacy credential file), its configuration is unchanged (hashed passwords, a failed login is final), andcredentials.xmlparses, keepscloudimg-adminand holds only strong hashes.hivemq-auth-guardruns 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 thatcloudimg-adminis accepted. If anything is off it stops the broker, so no listener is left open.hivemq-auth-watchrepeats 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, cloudimg-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 it, journalctl -u hivemq-auth-watch shows why.
Step 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:1883only (handy for scripts on the instance, still with a login), and the configuration gate refuses to start it with 1883 on any other address. Usemqtts://<host>:8883from 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>) and 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; the gate refuses a changed one (for example one that adds JMX). Logs go to the journal only (
journalctl -u hivemq), and they never contain a password: a failed login is logged asAuthentication failed because of invalid credentials.
Step 11: Check everything at once
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, cloudimg-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: cloudimg-admin and cloudimg-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: cloudimg-app refused outside cloudimg/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
Step 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 certificate is re-issued 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
sudo hivemq-set-hostname <name> goes back to a new self-signed certificate. The keystore and its password (/etc/hivemq/tls/keystore.env, root only) are rebuilt by these helpers; 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,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'sconf/credentials.xml, 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 (clustering and the Control Center are HiveMQ Enterprise features). The Java heap is half the instance's memory; size the instance for your connection count and message rate.
Support
cloudimg provides support for this image. Contact support@cloudimg.co.uk with the instance ID and the output of sudo hivemq-selfcheck (it never prints a password).