Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Mqtt Mosquitto Ubuntu
GUIDEInstall Guides

How to Install Eclipse Mosquitto MQTT Broker on Ubuntu 24.04 VPS: IoT Messaging Setup

28 min read

How to Install Eclipse Mosquitto MQTT Broker on Ubuntu 24.04 VPS: IoT Messaging Setup

MQTT is the de facto messaging protocol for IoT, home automation, industrial telemetry, and any system that needs lightweight publish/subscribe communication over unreliable networks. Eclipse Mosquitto is the reference open-source MQTT broker: small, fast, and production-proven on everything from Raspberry Pis to multi-million-device deployments. This guide walks you through installing Mosquitto on an Ubuntu 24.04 VPS with authentication, access control lists, TLS, WebSockets, bridging, and a hardened systemd configuration.

Need a VPS to run Mosquitto? Mosquitto is extremely lightweight — a single broker can handle thousands of concurrent clients on 1 GB of RAM. CloudCore Starter has more than enough capacity for most personal and small-business IoT deployments.

Table of Contents

  • What is MQTT and Mosquitto?
  • Why Self-Host an MQTT Broker?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Mosquitto and Clients
  • Step 3: Verify the Default Installation
  • Step 4: Configure Authentication
  • Step 5: Set Up Access Control Lists
  • Step 6: Configure Listeners (1883, 8883 TLS, 8884 WebSockets)
  • Step 7: Obtain Let's Encrypt TLS Certificates
  • Step 8: Enable Persistence and Logging
  • Step 9: Configure the Firewall with UFW
  • Step 10: Test Pub/Sub End to End
  • Step 11: Set Up Broker Bridging
  • Step 12: Harden the systemd Service
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is MQTT and Mosquitto?

    MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe messaging protocol designed for constrained devices and unreliable networks. Clients connect to a central broker and either publish messages to named topics or subscribe to topics they care about. The broker routes every incoming message to all subscribers of the matching topic. This decoupling — publishers do not know who is listening, and subscribers do not know who is sending — makes MQTT ideal for fan-out telemetry, command-and-control, and device-to-device messaging at scale.

    MQTT supports three Quality of Service (QoS) levels (0 = at most once, 1 = at least once, 2 = exactly once), retained messages so late-joining subscribers receive the last known value, Last Will and Testament messages that fire when a client disconnects unexpectedly, and a binary wire format that is dramatically smaller than HTTP or AMQP — a typical sensor message is under 20 bytes.

    Eclipse Mosquitto is the Eclipse Foundation's open-source implementation of an MQTT broker, written in C. It supports MQTT versions 3.1, 3.1.1, and 5.0, plus MQTT over WebSockets, TLS encryption, bridging to other brokers, dynamic security plugins, and a full client library. Mosquitto is the broker behind Home Assistant, Node-RED, AWS IoT Greengrass, Azure IoT Edge, and countless industrial deployments. The single binary is under 200 KB, starts in milliseconds, and routinely sustains tens of thousands of concurrent clients per broker on modest hardware.

    Why Self-Host an MQTT Broker?

    Managed cloud brokers (AWS IoT Core, HiveMQ Cloud, Azure IoT Hub, EMQX Cloud) are convenient, but self-hosting Mosquitto on your own VPS has concrete benefits:

    • Flat-rate cost, no per-message charges — AWS IoT charges roughly $1 per million messages plus per-device connectivity fees. A small fleet of 50 devices sending one message per minute easily costs $30–$80 per month. A Mosquitto VPS handles the same load for the cost of the VPS itself, regardless of message volume.
    • No device count limits — Cloud brokers price per connected device or per session. Your own broker accepts any number of clients within the hardware's capacity (typically 10,000+ concurrent connections on 1 vCPU).
    • Complete data sovereignty — All telemetry, sensor readings, camera triggers, and control commands stay on infrastructure you own. No third party sees the traffic, which matters for industrial control systems, medical devices, and GDPR-regulated deployments.
    • Unlimited retained messages and topic depth — Cloud brokers cap retained message size, payload size, and topic hierarchy depth. Mosquitto has no hard limits other than RAM.
    • Bridging flexibility — Connect multiple Mosquitto brokers across sites, bridge to cloud providers selectively, or mirror topics for redundancy. Cloud brokers restrict this.
    • Local-network low latency — When your broker, Home Assistant, and Node-RED all run on the same VPS or LAN, round-trip time is under 1 ms. Cloud brokers add 30–100 ms per hop.
    • Full protocol control — Enable MQTT 5.0 features, custom authentication plugins, and non-standard ports without waiting for a managed provider to add support.

    Cost Comparison: Mosquitto VPS vs. Cloud IoT Brokers

    ScenarioAWS IoT CoreHiveMQ CloudSelf-Hosted Mosquitto (VPS)
    50 devices, 1 msg/min~$5–15/mo$50+/moIncluded in VPS
    500 devices, 1 msg/min~$30–80/mo$199+/moIncluded in VPS
    5,000 devices, 1 msg/min~$200+/moEnterprise tierIncluded in VPS
    Data egressExtra per GBIncluded at tierIncluded in VPS bandwidth
    TLS / client certsExtra configYesYes (this guide)
    WebSocketsYesYesYes (this guide)
    Bridging to other brokersLimitedLimitedUnlimited
    For most hobbyist, smart-home, and small-industrial deployments, a single CloudCore Starter VPS replaces a cloud broker entirely and pays for itself within the first billing cycle.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • A domain name pointing to the VPS public IP (required for Let's Encrypt TLS in Step 7) — e.g. mqtt.yourdomain.com
    • Ports 1883, 8883, 8884, and 80 (for certificate renewal) reachable from the networks your clients will connect from
    • At least 1 GB of RAM and 1 vCPU — Mosquitto is extremely lightweight
    Recommended Plan: CloudCore Starter
    >
    For a personal or small-business MQTT broker serving a few hundred devices, the CloudCore Starter plan is more than enough:
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 50 GB NVMe SSD
    - Unmetered bandwidth
    >
    This gives you headroom to run Mosquitto alongside Home Assistant, Node-RED, or InfluxDB on the same server if you want a complete self-hosted IoT stack.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start with an up-to-date package index and base system.

    bash
    sudo apt update && sudo apt upgrade -y

    If the kernel was upgraded, reboot before continuing:

    bash
    sudo reboot

    Step 2: Install Mosquitto and Clients

    Ubuntu 24.04 ships Mosquitto in the default repositories, but the mosquitto-dev PPA provides the latest stable 2.x release with MQTT 5.0 improvements. For most users the distro version is fine — install the broker and the CLI clients together:

    bash
    sudo apt install -y mosquitto mosquitto-clients

    The mosquitto package installs:

    • /usr/sbin/mosquitto — the broker binary
    • /etc/mosquitto/mosquitto.conf — the main configuration file
    • /etc/mosquitto/conf.d/ — drop-in directory for additional config snippets
    • A systemd unit at /lib/systemd/system/mosquitto.service
    • A mosquitto system user/group
    The mosquitto-clients package provides mosquitto_pub and mosquitto_sub — the two CLI tools you use for manual testing.

    Confirm the installed version:

    bash
    mosquitto -h | head -5

    Expected output:

    text
    mosquitto version 2.0.18
    mosquitto is an MQTT v5.0/v3.1.1/v3.1 broker.

    Step 3: Verify the Default Installation

    The default install starts Mosquitto listening on 127.0.0.1:1883 with anonymous access allowed locally. Check the service status:

    bash
    sudo systemctl status mosquitto

    Expected output:

    text
    ● mosquitto.service - Mosquitto MQTT Broker
         Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; preset: enabled)
         Active: active (running) since Wed 2026-04-16 10:00:00 UTC; 30s ago
       Main PID: 1234 (mosquitto)

    Run a quick smoke test. In one terminal subscribe to a test topic:

    bash
    mosquitto_sub -h localhost -t test/hello -v

    In a second SSH session publish a message:

    bash
    mosquitto_pub -h localhost -t test/hello -m "hello world"

    You should see test/hello hello world appear in the first terminal. The broker is alive. Now let's configure it properly.

    Step 4: Configure Authentication

    Anonymous access is fine for a local smoke test but unacceptable for anything reachable from the internet. Create a password file with one or more users.

    Create an empty password file and add a user named iotuser:

    bash
    sudo mosquitto_passwd -c /etc/mosquitto/passwd iotuser

    You will be prompted to enter and confirm a password. The -c flag creates the file (and overwrites any existing one). To add additional users without wiping the file, omit -c:

    bash
    sudo mosquitto_passwd /etc/mosquitto/passwd homeassistant
    sudo mosquitto_passwd /etc/mosquitto/passwd nodered

    Lock down the file:

    bash
    sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
    sudo chmod 640 /etc/mosquitto/passwd

    Inspect the file (passwords are hashed with PBKDF2-SHA512):

    bash
    sudo cat /etc/mosquitto/passwd

    Expected output:

    text
    iotuser:$7$101$abc...xyz$def...uvw==
    homeassistant:$7$101$...
    nodered:$7$101$...

    You will reference this file from mosquitto.conf in Step 6.

    Step 5: Set Up Access Control Lists

    Authentication proves who a client is; an ACL controls what topics that client can publish to or subscribe to. This is critical on a shared broker — you do not want a compromised sensor to publish fake commands to your door lock topic.

    Create /etc/mosquitto/acl:

    bash
    sudo tee /etc/mosquitto/acl > /dev/null <<'EOF'
    

    ===== Default: no access unless explicitly granted =====

    ----- iotuser: full read/write under sensors/ and devices/ -----

    user iotuser topic readwrite sensors/# topic readwrite devices/# topic read $SYS/#

    ----- homeassistant: full access under home/ and homeassistant/ -----

    user homeassistant topic readwrite home/# topic readwrite homeassistant/# topic read sensors/# topic read $SYS/#

    ----- nodered: read everything, publish only to automation/ -----

    user nodered topic read # topic write automation/#

    ----- Pattern ACLs: each client gets a private namespace by username -----

    pattern readwrite clients/%u/# EOF

    Set permissions:

    bash
    sudo chown mosquitto:mosquitto /etc/mosquitto/acl
    sudo chmod 640 /etc/mosquitto/acl

    Key syntax:

    • user <name> — following rules apply to that username until the next user line
    • topic readwrite <pattern> — grant publish + subscribe access (read = subscribe only, write = publish only)
    • # — multi-level wildcard; + — single-level wildcard
    • pattern — template rules; %u expands to the connecting username, %c to the client ID. clients/%u/# gives every user a private subtree
    • $SYS/# — Mosquitto's internal telemetry topics (broker stats, uptime, connected clients)

    Step 6: Configure Listeners

    Now wire the password file and ACL into Mosquitto, and add three listeners: plain MQTT on localhost:1883 for local apps, TLS-encrypted MQTT on :8883 for internet clients, and WebSockets on :8884 for browser-based clients.

    Replace the main config with a clean, annotated version:

    bash
    sudo tee /etc/mosquitto/mosquitto.conf > /dev/null <<'EOF'
    

    ========== Global settings ==========

    pid_file /run/mosquitto/mosquitto.pid

    persistence true persistence_location /var/lib/mosquitto/

    log_dest file /var/log/mosquitto/mosquitto.log log_type error log_type warning log_type notice log_type information connection_messages true log_timestamp true

    Security defaults

    allow_anonymous false password_file /etc/mosquitto/passwd acl_file /etc/mosquitto/acl

    Load any drop-in configs

    include_dir /etc/mosquitto/conf.d

    ========== Listener 1: plain MQTT, localhost only ==========

    listener 1883 127.0.0.1 protocol mqtt

    ========== Listener 2: MQTT over TLS (public) ==========

    listener 8883 protocol mqtt cafile /etc/letsencrypt/live/mqtt.yourdomain.com/chain.pem certfile /etc/letsencrypt/live/mqtt.yourdomain.com/fullchain.pem keyfile /etc/letsencrypt/live/mqtt.yourdomain.com/privkey.pem tls_version tlsv1.2

    ========== Listener 3: MQTT over WebSockets (public, TLS) ==========

    listener 8884 protocol websockets cafile /etc/letsencrypt/live/mqtt.yourdomain.com/chain.pem certfile /etc/letsencrypt/live/mqtt.yourdomain.com/fullchain.pem keyfile /etc/letsencrypt/live/mqtt.yourdomain.com/privkey.pem tls_version tlsv1.2 EOF

    Replace mqtt.yourdomain.com throughout with your actual hostname. We will generate the certificates in the next step.

    Key directives explained:

    • allow_anonymous false — Every client must authenticate. Anonymous connects are rejected.
    • listener 1883 127.0.0.1 — Plain MQTT on port 1883, bound to localhost only. Perfect for apps running on the same VPS (Home Assistant, Node-RED, custom scripts) that do not need the overhead of TLS.
    • listener 8883 (no bind address) — TLS MQTT on the standard MQTT-over-TLS port, listening on all interfaces.
    • listener 8884 — MQTT over WebSockets, the standard for browser clients using libraries like MQTT.js or Paho JavaScript.
    • protocol websockets — Must be set explicitly; without it the port would speak raw MQTT.
    • tls_version tlsv1.2 — Minimum TLS version. Mosquitto 2.x supports 1.3 automatically if OpenSSL does; setting 1.2 as the floor ensures compatibility with ESP8266/ESP32 devices that lack 1.3 support.
    Do not restart Mosquitto yet — the TLS listeners will fail until certificates exist.

    Step 7: Obtain Let's Encrypt TLS Certificates

    Install Certbot and request a certificate for your MQTT hostname. Because Mosquitto does not serve HTTP, use Certbot's standalone mode on port 80.

    bash
    sudo apt install -y certbot

    Temporarily free port 80 (skip this if no web server is running):

    bash
    sudo systemctl stop nginx 2>/dev/null || true
    sudo systemctl stop apache2 2>/dev/null || true

    Request the certificate:

    bash
    sudo certbot certonly --standalone \
      -d mqtt.yourdomain.com \
      --agree-tos \
      --email [email protected] \
      --non-interactive

    Expected output:

    text
    Successfully received certificate.
    Certificate is saved at: /etc/letsencrypt/live/mqtt.yourdomain.com/fullchain.pem
    Key is saved at:         /etc/letsencrypt/live/mqtt.yourdomain.com/privkey.pem
    This certificate expires on 2026-07-15.

    Grant Mosquitto Access to the Certificates

    Let's Encrypt stores private keys with restrictive permissions. Mosquitto runs as the mosquitto user and cannot read them by default. Add mosquitto to the ssl-cert group and apply group-readable permissions to the live/ and archive/ directories:

    bash
    sudo usermod -aG ssl-cert mosquitto
    sudo chgrp -R ssl-cert /etc/letsencrypt/live /etc/letsencrypt/archive
    sudo chmod -R g+rX /etc/letsencrypt/live /etc/letsencrypt/archive

    Auto-Reload Mosquitto on Certificate Renewal

    Certbot renews automatically via a systemd timer, but Mosquitto will not pick up the new certificate until it is reloaded. Add a deploy hook:

    bash
    sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
    sudo tee /etc/letsencrypt/renewal-hooks/deploy/mosquitto-reload.sh > /dev/null <<'EOF'
    #!/bin/bash
    systemctl reload mosquitto
    EOF
    sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto-reload.sh

    Now restart Mosquitto to pick up the full config:

    bash
    sudo systemctl restart mosquitto
    sudo systemctl status mosquitto

    Verify all three listeners are bound:

    bash
    sudo ss -tlnp | grep mosquitto

    Expected output:

    text
    LISTEN 0  100  127.0.0.1:1883  0.0.0.0:*  users:(("mosquitto",pid=1234,fd=5))
    LISTEN 0  100    0.0.0.0:8883  0.0.0.0:*  users:(("mosquitto",pid=1234,fd=6))
    LISTEN 0  100    0.0.0.0:8884  0.0.0.0:*  users:(("mosquitto",pid=1234,fd=7))

    Step 8: Enable Persistence and Logging

    Persistence was already enabled in the main config (persistence true). This means retained messages, queued QoS 1/2 messages for offline clients, and subscription state survive broker restarts — stored in /var/lib/mosquitto/mosquitto.db.

    Fine-tune persistence behaviour with a drop-in snippet:

    bash
    sudo tee /etc/mosquitto/conf.d/persistence.conf > /dev/null <<'EOF'
    

    Write the persistence DB to disk every 30 minutes or every 1000 changes

    autosave_interval 1800 autosave_on_changes false

    Keep retained messages and offline client state for 14 days

    persistent_client_expiration 14d

    Max message size (256 KB should cover most IoT payloads; raise for firmware OTA)

    message_size_limit 262144

    Per-client inflight + queued message limits (prevent memory exhaustion)

    max_inflight_messages 40 max_queued_messages 1000 EOF

    Logs already go to /var/log/mosquitto/mosquitto.log. Ubuntu's default logrotate config at /etc/logrotate.d/mosquitto handles weekly rotation with compression, so no further action is needed.

    Reload the config:

    bash
    sudo systemctl reload mosquitto

    Check that the persistence DB exists after a few minutes of broker activity:

    bash
    sudo ls -lh /var/lib/mosquitto/

    Expected output:

    text
    -rw------- 1 mosquitto mosquitto 4.0K Apr 16 10:15 mosquitto.db

    Step 9: Configure the Firewall with UFW

    Open only the ports you actually serve. Port 1883 stays closed at the firewall level — it is already bound to 127.0.0.1 only, but defense-in-depth is cheap.

    bash
    sudo ufw allow OpenSSH
    sudo ufw allow 8883/tcp comment 'MQTT over TLS'
    sudo ufw allow 8884/tcp comment 'MQTT over WebSockets'
    sudo ufw allow 80/tcp comment 'Certbot HTTP challenge'
    sudo ufw --force enable
    sudo ufw status verbose

    Expected output:

    text
    Status: active

    To Action From -- ------ ---- 22/tcp (OpenSSH) ALLOW IN Anywhere 8883/tcp ALLOW IN Anywhere # MQTT over TLS 8884/tcp ALLOW IN Anywhere # MQTT over WebSockets 80/tcp ALLOW IN Anywhere # Certbot HTTP challenge

    If you know every client's static IP, tighten further:

    bash
    sudo ufw delete allow 8883/tcp
    sudo ufw allow from 203.0.113.10 to any port 8883 proto tcp
    sudo ufw allow from 198.51.100.0/24 to any port 8883 proto tcp

    Step 10: Test Pub/Sub End to End

    Validate every listener with the CLI clients.

    Local plain MQTT (port 1883)

    bash
    # Subscriber (terminal 1)
    mosquitto_sub -h localhost -p 1883 -u iotuser -P 'yourpassword' -t 'sensors/#' -v

    Publisher (terminal 2)

    mosquitto_pub -h localhost -p 1883 -u iotuser -P 'yourpassword' \ -t 'sensors/livingroom/temp' -m '22.4'

    You should see sensors/livingroom/temp 22.4 on the subscriber.

    TLS MQTT (port 8883)

    From any client with network access to your VPS:

    bash
    mosquitto_sub -h mqtt.yourdomain.com -p 8883 \
      -u iotuser -P 'yourpassword' \
      --capath /etc/ssl/certs/ \
      -t 'sensors/#' -v
    bash
    mosquitto_pub -h mqtt.yourdomain.com -p 8883 \
      -u iotuser -P 'yourpassword' \
      --capath /etc/ssl/certs/ \
      -t 'sensors/outdoor/temp' -m '15.1'

    The --capath /etc/ssl/certs/ tells the client to validate the server certificate against the system CA bundle, which includes the Let's Encrypt root.

    WebSockets (port 8884) from a browser

    Use mqttx.app or the HiveMQ WebSocket client with these settings:

    • Host: mqtt.yourdomain.com
    • Port: 8884
    • Path: /mqtt (or blank)
    • TLS: enabled (wss://)
    • Username / password: one of the accounts you created
    Publish and subscribe to sensors/# from the browser and confirm messages flow both directions.

    ACL enforcement test

    Attempt a write that the ACL forbids:

    bash
    mosquitto_pub -h localhost -u nodered -P 'yourpassword' \
      -t 'sensors/shouldfail' -m 'nope'

    Check the log:

    bash
    sudo tail -20 /var/log/mosquitto/mosquitto.log

    Expected output:

    text
    Denied PUBLISH from nodered (u'nodered', t'sensors/shouldfail')

    Good — the ACL is working.

    Step 11: Set Up Broker Bridging

    A bridge is a persistent MQTT connection from your broker to another broker that mirrors selected topics. Use cases include mirroring a remote site's sensors to a central broker, selectively forwarding telemetry to a cloud broker (AWS IoT, HiveMQ Cloud) while keeping control traffic local, and setting up active/active redundancy.

    Create a bridge config snippet:

    bash
    sudo tee /etc/mosquitto/conf.d/bridge.conf > /dev/null <<'EOF'
    

    ===== Bridge to a remote broker =====

    connection bridge-to-central address central.example.com:8883 bridge_protocol_version mqttv50

    Authentication on the remote side

    remote_username bridgeuser remote_password changeme

    TLS

    bridge_cafile /etc/ssl/certs/ca-certificates.crt bridge_insecure false

    Topics to forward:

    topic <pattern> <direction> <qos> <local-prefix> <remote-prefix>

    direction: out = publish local -> remote

    in = subscribe on remote, publish locally

    both = bidirectional

    topic sensors/# out 1 "" siteA/ topic commands/# in 1 siteA/ ""

    Clean session / persistence

    cleansession false try_private true notifications true start_type automatic restart_timeout 10 30 EOF

    Explanation of the topic mapping:

    • topic sensors/# out 1 "" siteA/ — Every message published locally under sensors/ is forwarded to the remote broker with the prefix siteA/ (so sensors/livingroom/temp becomes siteA/sensors/livingroom/temp remotely). This is how multi-site aggregation works — each site publishes under its own prefix on the central broker.
    • topic commands/# in 1 siteA/ "" — The bridge subscribes to siteA/commands/# on the remote broker; incoming messages are re-published locally under commands/#, stripping the siteA/ prefix.
    Reload and check the bridge state:

    bash
    sudo systemctl reload mosquitto
    sudo journalctl -u mosquitto -n 20 --no-pager

    Expected output:

    text
    Connecting bridge (step 1) bridge-to-central (central.example.com:8883)
    Bridge bridge-to-central sending CONNECT

    If the remote side rejects authentication, the log will show Connection Refused: not authorised.

    Bridges survive network outages automatically — restart_timeout 10 30 means Mosquitto waits 10 seconds before the first reconnect attempt and backs off to 30 seconds.

    Step 12: Harden the systemd Service

    The stock systemd unit is fine, but a few hardening directives reduce the blast radius if Mosquitto is ever compromised. Create a drop-in override instead of editing the distro unit:

    bash
    sudo systemctl edit mosquitto

    Paste the following into the editor:

    ini
    [Service]
    

    Restart automatically on crash

    Restart=on-failure RestartSec=5

    Filesystem and privilege hardening

    NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true PrivateDevices=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true LockPersonality=true MemoryDenyWriteExecute=true RestrictRealtime=true RestrictNamespaces=true

    Allow writes only to the directories Mosquitto actually needs

    ReadWritePaths=/var/lib/mosquitto /var/log/mosquitto /run/mosquitto

    Resource limits

    LimitNOFILE=65536 TasksMax=4096

    Save and exit. Apply the changes:

    bash
    sudo systemctl daemon-reload
    sudo systemctl restart mosquitto
    sudo systemctl status mosquitto

    Verify the process can still write to its directories:

    bash
    sudo ls -la /var/lib/mosquitto/ /var/log/mosquitto/

    The LimitNOFILE=65536 bump is important at scale — each connected MQTT client consumes one file descriptor, and the default of 1024 caps you around 1000 concurrent clients.

    Troubleshooting

    ProblemCauseSolution
    Connection Refused: not authorisedWrong username/password or ACL blocks the topicRe-check mosquitto_passwd entry; tail /var/log/mosquitto/mosquitto.log for the denied topic pattern
    Unable to load certificate file on startupmosquitto user cannot read Let's Encrypt keysRe-run the chgrp -R ssl-cert + chmod g+rX commands from Step 7
    WebSockets client hangs on connectPort 8884 blocked or protocol websockets line missingsudo ufw status, check ss -tlnp \</td><td>grep 8884<code>, confirm </code>protocol websockets appears under the listener line
    Error: Address already in useAnother broker or stale process holds the portsudo lsof -i :1883; kill the conflicting process
    Bridge stays in step 1 foreverTLS CA file missing, hostname wrong, or remote blocks IPSet bridge_insecure true temporarily to isolate TLS vs auth; check remote broker logs
    Retained messages lost after restartpersistence true missing or /var/lib/mosquitto not writableConfirm persistence true in mosquitto.conf; check ls -la /var/lib/mosquitto/
    Mosquitto dies under load with Too many open filesDefault LimitNOFILE too lowApply the systemd override from Step 12 (LimitNOFILE=65536)
    ESP32/ESP8266 cannot connect over TLSDevice clock wrong or root CA missing from firmwareSync NTP on the device; embed the ISRG Root X1 certificate in firmware

    Useful diagnostic commands

    bash
    # Live broker logs
    sudo journalctl -u mosquitto -f

    Mosquitto-specific log file

    sudo tail -f /var/log/mosquitto/mosquitto.log

    Built-in broker telemetry (requires subscribe access to $SYS)

    mosquitto_sub -h localhost -u iotuser -P 'yourpassword' -t '$SYS/#' -v

    Port 8883 TLS handshake test

    openssl s_client -connect mqtt.yourdomain.com:8883 -servername mqtt.yourdomain.com </dev/null

    The $SYS/# tree exposes broker stats in real time: connected clients, messages received, bytes sent, uptime, subscriptions. Feed these into Prometheus via mosquitto_exporter for dashboards.

    FAQ

    How many MQTT clients can a single Mosquitto broker handle?

    A single Mosquitto 2.x instance on a 2 vCPU / 4 GB VPS comfortably handles 10,000–50,000 concurrent clients at low-to-moderate message rates (1 message per client per minute). Raw throughput exceeds 100,000 messages per second on modest hardware because MQTT's binary framing is cheap and Mosquitto's event loop is single-threaded but highly efficient. The practical ceiling is usually file descriptors (raise LimitNOFILE per Step 12) and RAM for retained messages, not CPU. For six-figure client counts or multi-million messages per second, consider EMQX or VerneMQ, which scale across cores.

    Should I use plain MQTT (1883) or TLS (8883)?

    Anything that traverses the internet must use TLS. The overhead on modern hardware is negligible — Mosquitto adds under 1 ms of latency per message, and AES-GCM on even a low-end ARM Cortex-M33 MCU easily keeps up with typical IoT message rates. Use the plain 1883 listener only for localhost-bound inter-process communication between apps on the same VPS. If you need plain MQTT across a LAN, bind it to the internal interface only (e.g. listener 1883 10.0.0.1) and restrict with UFW.

    Do I need client certificates as well as username/password?

    Mutual TLS (mTLS) with client certificates adds a second factor: a device must possess a valid private key and know its password. It is excellent for fleets where you control provisioning — each device gets a unique certificate baked in at manufacture time, and revoking a compromised device is a matter of removing one line from a CRL. For hobby setups, username/password over TLS is sufficient. To enable mTLS, add require_certificate true and use_identity_as_username true to a listener, then issue certificates signed by your own CA. The Mosquitto TLS documentation at mosquitto.org/documentation/ has a complete walkthrough.

    How do I monitor broker health?

    Three complementary approaches. First, the built-in $SYS/# topic tree exposes dozens of metrics — $SYS/broker/clients/connected, $SYS/broker/messages/received, $SYS/broker/load/messages/sent/1min, and so on. Subscribe to them with mosquitto_sub or feed them into any MQTT-aware dashboard. Second, install the Prometheus mosquitto_exporter to scrape $SYS into Prometheus and visualize in Grafana. Third, use Uptime Kuma's MQTT probe type to alert if the broker stops responding or if a heartbeat topic goes stale. For production deployments, all three together give you deep visibility.

    Can Mosquitto store messages for offline clients?

    Yes, with QoS 1 or QoS 2 and clean_session=false set by the client on connect. When a subscriber with a persistent session disconnects, Mosquitto queues matching messages up to max_queued_messages per client (1000 by default in our config). On reconnect, the broker replays the queue. This is how battery-powered devices that wake up briefly every hour receive commands issued while they were asleep. Retained messages are different — they store the last value on a topic and deliver it once to each new subscriber regardless of sessions.

    How do I migrate from AWS IoT Core or HiveMQ Cloud?

    Most client libraries (Paho, MQTT.js, ESP-MQTT) only need a hostname, port, username, and password change to switch brokers. The wire protocol is identical. The main migration work is: recreate users and ACLs (Step 4–5), reissue any client certificates if you used mTLS, update device firmware with the new hostname, and rebuild any cloud-broker-specific features you depended on (AWS IoT Rules, shadows, jobs). For AWS IoT Device Shadow equivalents on Mosquitto, pair it with Node-RED or a small custom service that maintains last-known-state on retained topics.

    Next Steps

    Now that Mosquitto is running, here are the natural additions for a complete self-hosted IoT stack:

    • Install Home Assistant — Hook Home Assistant into your Mosquitto broker for the most popular open-source home automation platform. The MQTT integration auto-discovers devices published with the Home Assistant discovery schema. See How to Install Home Assistant on Ubuntu.
    • Install Node-RED — Flow-based visual programming for IoT. Drag MQTT in/out nodes onto a canvas and wire sensor data into dashboards, databases, HTTP calls, and automations without writing code. See How to Install Node-RED on Ubuntu.
    • Install n8n — A more general-purpose workflow automation platform with a first-class MQTT trigger node. Ideal for integrating IoT events with business systems (Slack alerts, Google Sheets logging, CRM updates). See How to Install n8n on Ubuntu.
    • Store telemetry in InfluxDB or TimescaleDB — Mosquitto is a message bus, not a database. Pair it with a time-series database and Telegraf's MQTT consumer input to persist every sensor reading for dashboards and historical analysis.
    • Graph live data with Grafana — Connect Grafana to InfluxDB (or directly to MQTT via the MQTT data source plugin) for live dashboards of every topic.
    • Read the official Mosquitto documentation — mosquitto.org/documentation/ covers advanced topics including the dynamic security plugin, custom auth plugins, cluster-style deployments, and MQTT 5 features like shared subscriptions and topic aliases.

    Need a VPS for your MQTT broker?
    >
    CloudCore Starter gives you a 2 vCPU / 4 GB RAM / 50 GB NVMe VPS that comfortably runs Mosquitto plus Home Assistant, Node-RED, and InfluxDB on the same machine — the full self-hosted IoT stack on one server.
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 50 GB NVMe SSD
    - Unmetered bandwidth
    - Root SSH access, Ubuntu 24.04
    >
    Deploy your IoT VPS now

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket