tutorial

How to Monitor HiveMQ with Vigilmon

HiveMQ powers enterprise MQTT infrastructure for IoT deployments at scale — but silent broker node failures, session store bloat, and extension health degradation can disconnect thousands of devices. Learn how to monitor HiveMQ broker health, client sessions, message throughput, cluster state, and extensions with Vigilmon.

HiveMQ is the enterprise MQTT broker that keeps industrial sensors, connected vehicles, smart home devices, and telemetry pipelines running. Unlike general-purpose message brokers, HiveMQ is built for massive MQTT client concurrency — hundreds of thousands of persistent sessions, retained message stores that survive restarts, and clustering with zero-downtime rolling upgrades.

But HiveMQ failures hit hard: a node leaving the cluster silently redistributes sessions across remaining nodes, a retained message store that grows without bound eventually slows publishes, and a malfunctioning extension can degrade the entire broker without crashing it. Vigilmon gives you external visibility into HiveMQ health through its built-in REST management API and heartbeat monitors for your MQTT consumer services.


Why HiveMQ Needs External Monitoring

HiveMQ ships with Control Center (the web UI) and exposes metrics via Prometheus. But those require active watching. External monitoring with Vigilmon adds:

  • Proactive alerting when node health REST endpoints return errors or nodes leave the cluster
  • Client session count monitoring so you know when device connections start dropping
  • Message throughput anomaly detection via a health sidecar that tracks publish and subscribe rates
  • Retained message store size tracking before it impacts publish latency
  • Extension health checks for critical HiveMQ extensions (bridge, enterprise security)
  • Heartbeat monitoring for MQTT subscriber applications that must prove they are actively processing

Step 1: Enable the HiveMQ REST Management API

HiveMQ Enterprise exposes a REST API for cluster and broker management. Configure it in config.xml:

<!-- config.xml -->
<rest-api>
  <enabled>true</enabled>
  <listeners>
    <http-listener>
      <port>8888</port>
      <bind-address>0.0.0.0</bind-address>
    </http-listener>
  </listeners>
</rest-api>

Restart HiveMQ and verify the API is up:

# Get cluster node list
curl -u admin:admin http://localhost:8888/api/v1/nodes

# Get broker health
curl -u admin:admin http://localhost:8888/api/v1/health

# Get all connected clients count
curl -u admin:admin http://localhost:8888/api/v1/mqtt/clients

For HiveMQ Community Edition, the REST API is not available — use the Prometheus metrics endpoint instead (see Step 3).


Step 2: Build a HiveMQ Health Endpoint

Write a lightweight health sidecar that queries HiveMQ's REST API and surfaces a clean /health endpoint for Vigilmon:

# hivemq_health.py
from flask import Flask, jsonify
import requests, os

app = Flask(__name__)

HIVEMQ_API    = os.environ.get('HIVEMQ_API_URL', 'http://localhost:8888/api/v1')
HIVEMQ_USER   = os.environ.get('HIVEMQ_API_USER', 'admin')
HIVEMQ_PASS   = os.environ.get('HIVEMQ_API_PASS', 'admin')
SESSION_DROP_THRESHOLD = float(os.environ.get('HIVEMQ_SESSION_DROP_THRESHOLD', '0.10'))
RETAINED_MSG_LIMIT     = int(os.environ.get('HIVEMQ_RETAINED_MSG_LIMIT', '100000'))

def api_get(path):
    r = requests.get(f"{HIVEMQ_API}{path}",
                     auth=(HIVEMQ_USER, HIVEMQ_PASS), timeout=5)
    r.raise_for_status()
    return r.json()

@app.route('/health/hivemq')
def health():
    issues = []

    # Node health
    try:
        health_data = api_get('/health')
        if health_data.get('status') != 'HEALTHY':
            issues.append(f"broker_status_{health_data.get('status', 'unknown')}")
    except Exception as e:
        return jsonify(status='down', reason=str(e)), 503

    # Cluster nodes
    nodes = api_get('/nodes').get('items', [])
    unhealthy_nodes = [n for n in nodes if n.get('status') != 'RUNNING']
    if unhealthy_nodes:
        issues.append(f"unhealthy_nodes_{len(unhealthy_nodes)}")

    if issues:
        return jsonify(status='degraded', issues=issues,
                       total_nodes=len(nodes)), 503

    return jsonify(
        status='ok',
        total_nodes=len(nodes),
        healthy_nodes=len(nodes) - len(unhealthy_nodes),
    ), 200

@app.route('/health/hivemq/sessions')
def sessions():
    issues = []

    clients = api_get('/mqtt/clients')
    total = clients.get('total', 0)
    connected = sum(1 for c in clients.get('items', [])
                    if c.get('connected'))

    # Alert if connected fraction drops sharply
    if total > 0 and (connected / total) < (1.0 - SESSION_DROP_THRESHOLD):
        issues.append(f"connected_clients_{connected}_of_{total}")

    if issues:
        return jsonify(status='degraded', issues=issues,
                       total=total, connected=connected), 503

    return jsonify(status='ok', total=total, connected=connected), 200

@app.route('/health/hivemq/retained')
def retained():
    try:
        # HiveMQ EE: retained messages count via REST
        retained = api_get('/mqtt/retained-messages')
        count = retained.get('total', 0)
        if count > RETAINED_MSG_LIMIT:
            return jsonify(
                status='degraded',
                reason='retained_message_store_bloat',
                count=count,
                limit=RETAINED_MSG_LIMIT,
            ), 503
        return jsonify(status='ok', retained_count=count), 200
    except Exception as e:
        return jsonify(status='unknown', error=str(e)), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=3007)

Step 3: Prometheus Metrics Endpoint

HiveMQ can expose Prometheus metrics via the HiveMQ Prometheus extension (Community and Enterprise):

<!-- hivemq-prometheus-extension/prometheusextension.properties -->
port=9399
bind-address=0.0.0.0
metric-path=/metrics

Verify the metrics endpoint:

curl http://localhost:9399/metrics | grep hivemq_

Key HiveMQ Prometheus metrics to watch:

| Metric | Alert condition | |---|---| | hivemq_networking_connections_current | Drops >10% in 5 minutes | | hivemq_messages_incoming_publish_rate | Falls to 0 unexpectedly | | hivemq_messages_outgoing_publish_rate | Falls to 0 unexpectedly | | hivemq_retain_messages_current | Exceeds capacity threshold | | hivemq_cluster_nodes_count | Drops below expected cluster size |

Build a Prometheus health probe:

@app.route('/health/hivemq/prometheus')
def prometheus_health():
    r = requests.get('http://localhost:9399/metrics', timeout=5)
    if r.status_code == 200 and 'hivemq_' in r.text:
        # Parse connection count from Prometheus text format
        for line in r.text.splitlines():
            if line.startswith('hivemq_networking_connections_current'):
                conn_count = float(line.split()[-1])
                return jsonify(status='ok', connections=int(conn_count)), 200
        return jsonify(status='ok'), 200
    return jsonify(status='down', reason='prometheus_endpoint_unavailable'), 503

Step 4: Extension Health Monitoring

HiveMQ extensions (bridge, enterprise security, Kafka extension) run in-process. A misbehaving extension can degrade the broker without crashing it. Check extension status via the REST API:

@app.route('/health/hivemq/extensions')
def extensions():
    try:
        ext_list = api_get('/extensions')
        unhealthy = [e for e in ext_list.get('items', [])
                     if e.get('enabled') and e.get('state') != 'STARTED']
        if unhealthy:
            return jsonify(
                status='degraded',
                reason='extensions_unhealthy',
                extensions=[e['id'] for e in unhealthy],
            ), 503
        return jsonify(
            status='ok',
            extension_count=len(ext_list.get('items', [])),
        ), 200
    except Exception as e:
        return jsonify(status='unknown', error=str(e)), 200

Step 5: Configure Vigilmon HTTP Monitors

  1. Log in to vigilmon.online and go to Monitors → New Monitor
  2. Choose HTTP / HTTPS
  3. Set the URL to your HiveMQ health endpoint: https://your-app.example.com/health/hivemq
  4. Set the check interval to 1 minute
  5. Under Expected response, configure:
    • Status code: 200
    • Response body contains: "status":"ok"
    • Response time threshold: 3000ms
  6. Under Alert channels, assign your Slack or PagerDuty integration
  7. Save the monitor

Add monitors for granular IoT broker coverage:

| Monitor URL | Purpose | Interval | |---|---|---| | /health/hivemq | Node health, cluster node count | 1 min | | /health/hivemq/sessions | Client connection count and drops | 1 min | | /health/hivemq/retained | Retained message store growth | 5 min | | /health/hivemq/extensions | Extension health (bridge, security) | 2 min | | /health/hivemq/prometheus | Prometheus metrics availability | 5 min |


Step 6: Heartbeat Monitoring for MQTT Consumer Services

In IoT architectures, the HiveMQ broker can be healthy while a backend subscriber service that processes device telemetry silently falls behind or crashes. Vigilmon heartbeat monitors detect this gap.

Set Up the Heartbeat Monitor

  1. In Vigilmon, go to Monitors → New Monitor → Heartbeat
  2. Set the name: hivemq-telemetry-processor
  3. Set the expected interval: 5 minutes
  4. Set the grace period: 10 minutes
  5. Save — copy the heartbeat URL: https://vigilmon.online/heartbeat/abc123xyz

Wire It Into Your MQTT Subscriber (Python — paho-mqtt)

# subscriber.py
import paho.mqtt.client as mqtt
import requests, os, time

VIGILMON_URL = os.environ['VIGILMON_HEARTBEAT_URL']
BROKER_HOST  = os.environ['HIVEMQ_HOST']
BROKER_PORT  = int(os.environ.get('HIVEMQ_PORT', '8883'))
TOPIC        = os.environ['MQTT_TOPIC']

msg_count = 0
last_heartbeat = time.time()
HEARTBEAT_EVERY_N = 200
HEARTBEAT_INTERVAL = 60

def on_message(client, userdata, msg):
    global msg_count, last_heartbeat
    process_telemetry(msg.payload)
    msg_count += 1

    now = time.time()
    if msg_count % HEARTBEAT_EVERY_N == 0 or now - last_heartbeat > HEARTBEAT_INTERVAL:
        try:
            requests.get(VIGILMON_URL, timeout=3)
        except Exception:
            pass
        last_heartbeat = now

def on_disconnect(client, userdata, rc):
    if rc != 0:
        print(f"Unexpected disconnect: {rc}")
        # Paho will auto-reconnect with reconnect_delay_set

def process_telemetry(payload):
    pass  # your processing logic

client = mqtt.Client(client_id="telemetry-processor", clean_session=False)
client.username_pw_set(os.environ['HIVEMQ_USER'], os.environ['HIVEMQ_PASS'])
client.tls_set()  # use TLS for port 8883
client.on_message = on_message
client.on_disconnect = on_disconnect
client.reconnect_delay_set(min_delay=1, max_delay=30)
client.connect(BROKER_HOST, BROKER_PORT, keepalive=60)
client.subscribe(TOPIC, qos=1)
client.loop_forever()

Node.js Subscriber (mqtt.js)

// subscriber.js
const mqtt = require('mqtt');
const axios = require('axios');

const client = mqtt.connect(`mqtts://${process.env.HIVEMQ_HOST}:8883`, {
  username: process.env.HIVEMQ_USER,
  password: process.env.HIVEMQ_PASS,
  clientId: 'telemetry-processor',
  clean: false,  // persistent session
  reconnectPeriod: 3000,
});

let msgCount = 0;
let lastHeartbeat = Date.now();
const HEARTBEAT_EVERY_N = 200;
const HEARTBEAT_INTERVAL_MS = 60_000;

client.on('message', (topic, payload) => {
  processTelemetry(payload);
  msgCount++;

  const now = Date.now();
  if (msgCount % HEARTBEAT_EVERY_N === 0 || now - lastHeartbeat > HEARTBEAT_INTERVAL_MS) {
    axios.get(process.env.VIGILMON_HEARTBEAT_URL).catch(() => {});
    lastHeartbeat = now;
  }
});

client.subscribe(process.env.MQTT_TOPIC, { qos: 1 });

Step 7: Alert Routing

| Monitor | Alert Channel | Priority | |---|---|---| | Node health /health/hivemq | Slack + PagerDuty | P1 | | Client sessions /health/hivemq/sessions | Slack + PagerDuty | P1 | | Extensions /health/hivemq/extensions | Slack | P2 | | Retained store /health/hivemq/retained | Slack | P2 | | Heartbeat: telemetry processor | Slack + email | P2 |

For IoT deployments, a sudden drop in client connections is usually more urgent than message throughput dips — devices with poor connectivity may reconnect naturally, but a coordinated drop (all devices losing sessions simultaneously) signals a broker-side issue. Configure the sessions monitor with a tight threshold and PagerDuty escalation.


Summary

HiveMQ powers IoT device connectivity at scale, and silent failures hit thousands of devices at once. External monitoring with Vigilmon catches these before device data stops flowing:

| Monitor Type | What It Covers | |---|---| | HTTP monitor on /health/hivemq | Broker node health, cluster node count | | HTTP monitor on /health/hivemq/sessions | Client connection count and session drops | | HTTP monitor on /health/hivemq/retained | Retained message store growth | | HTTP monitor on /health/hivemq/extensions | Extension health for bridge and security | | Heartbeat monitor | Subscriber application liveness |

Get started free at vigilmon.online — your first HiveMQ monitor is running in under two minutes.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →