developer-tools

Is Zigbee2MQTT Down? Real-Time Status & Outage Checker

Is Zigbee2MQTT Down? Real-Time Status & Outage Checker

Zigbee2MQTT is an open-source Zigbee-to-MQTT bridge with over 12,000 GitHub stars, allowing you to control Zigbee smart home devices — Philips Hue, IKEA Tradfri, Aqara temperature sensors, Sonoff switches, and thousands more — entirely via MQTT without vendor-specific hubs or cloud dependencies. It supports over 3,000 devices and integrates natively with Home Assistant via MQTT discovery, making it the de-facto standard for DIY Zigbee home automation. Zigbee2MQTT runs on a Raspberry Pi, a home server, or in Docker, paired with a Zigbee USB adapter such as the CC2531, Sonoff Zigbee Dongle Plus, or HUSBZB-1. The bridge translates Zigbee's proprietary protocol into plain JSON messages published over MQTT, exposing every sensor reading, switch state, and command as a readable topic any automation system can consume.

When Zigbee2MQTT goes offline, the consequences cascade immediately: lights cannot be toggled, motion sensors stop triggering automations, door/window sensors go silent, and temperature data vanishes. Because Zigbee devices communicate through the bridge — not directly to Home Assistant — a single bridge failure takes down the entire Zigbee mesh from the automation layer's perspective, even if the devices themselves are still powered and paired.

Quick Status Check

#!/bin/bash
# Zigbee2MQTT health check
# Checks MQTT bridge state, process, USB adapter, and broker connectivity

MQTT_HOST="${MQTT_HOST:-localhost}"
MQTT_PORT="${MQTT_PORT:-1883}"
ZIGBEE_ADAPTER="${ZIGBEE_ADAPTER:-/dev/ttyACM0}"
FAIL=0

echo "=== Zigbee2MQTT Status Check ==="
echo "MQTT broker: ${MQTT_HOST}:${MQTT_PORT}"
echo "Zigbee adapter: ${ZIGBEE_ADAPTER}"
echo ""

# Check MQTT broker port reachable
if nc -z -w 3 "${MQTT_HOST}" "${MQTT_PORT}" 2>/dev/null; then
  echo "[OK] MQTT broker port ${MQTT_PORT} is reachable"
else
  echo "[FAIL] MQTT broker port ${MQTT_PORT} not reachable"
  FAIL=1
fi

# Check Zigbee USB adapter exists
if [ -e "${ZIGBEE_ADAPTER}" ]; then
  echo "[OK] Zigbee adapter found at ${ZIGBEE_ADAPTER}"
else
  # Try alternative paths
  ALT=$(ls /dev/ttyACM* /dev/ttyUSB* /dev/serial/by-id/*zigbee* 2>/dev/null | head -1)
  if [ -n "$ALT" ]; then
    echo "[WARN] Adapter not at ${ZIGBEE_ADAPTER} but found at ${ALT}"
  else
    echo "[FAIL] Zigbee USB adapter not found — check udev rules or USB connection"
    FAIL=1
  fi
fi

# Check Zigbee2MQTT process or Docker container
if pgrep -f "zigbee2mqtt" > /dev/null 2>&1; then
  echo "[OK] Zigbee2MQTT process is running"
elif docker inspect zigbee2mqtt > /dev/null 2>&1; then
  STATE=$(docker inspect -f '{{.State.Status}}' zigbee2mqtt 2>/dev/null)
  if [ "$STATE" = "running" ]; then
    echo "[OK] Zigbee2MQTT Docker container is running"
  else
    echo "[FAIL] Zigbee2MQTT Docker container state: ${STATE}"
    FAIL=1
  fi
else
  echo "[WARN] Zigbee2MQTT process/container not detected"
fi

# Subscribe to bridge state topic briefly (requires mosquitto_sub)
if command -v mosquitto_sub > /dev/null 2>&1; then
  BRIDGE_STATE=$(timeout 5 mosquitto_sub -h "${MQTT_HOST}" -p "${MQTT_PORT}" \
    -t "zigbee2mqtt/bridge/state" -C 1 2>/dev/null)
  if echo "${BRIDGE_STATE}" | grep -q "online"; then
    echo "[OK] Bridge state topic reports: online"
  elif [ -n "${BRIDGE_STATE}" ]; then
    echo "[WARN] Bridge state topic reports: ${BRIDGE_STATE}"
    FAIL=1
  else
    echo "[WARN] No message received on zigbee2mqtt/bridge/state within 5s"
  fi
else
  echo "[INFO] mosquitto_sub not installed — skipping bridge state MQTT check"
fi

echo ""
if [ "$FAIL" -eq 0 ]; then
  echo "Result: Zigbee2MQTT appears healthy"
else
  echo "Result: Zigbee2MQTT has failures — review output above"
  exit 1
fi

Python Health Check

#!/usr/bin/env python3
"""
Zigbee2MQTT health check
Connects via MQTT to verify bridge state, device count, and last-seen timestamps
"""

import json
import os
import sys
import threading
import time
from datetime import datetime, timezone

try:
    import paho.mqtt.client as mqtt
except ImportError:
    print("ERROR: paho-mqtt not installed. Run: pip install paho-mqtt")
    sys.exit(1)

MQTT_HOST = os.environ.get("MQTT_HOST", "localhost")
MQTT_PORT = int(os.environ.get("MQTT_PORT", "1883"))
MQTT_USER = os.environ.get("MQTT_USER", "")
MQTT_PASS = os.environ.get("MQTT_PASS", "")
STALE_DEVICE_HOURS = float(os.environ.get("STALE_DEVICE_HOURS", "24"))
SUBSCRIBE_TIMEOUT = 8

results = {}
received = threading.Event()


def on_connect(client, userdata, flags, rc):
    if rc == 0:
        client.subscribe("zigbee2mqtt/bridge/state")
        client.subscribe("zigbee2mqtt/bridge/info")
        client.subscribe("zigbee2mqtt/bridge/devices")
    else:
        results["mqtt_connect"] = (False, f"MQTT connect failed rc={rc}")
        received.set()


def on_message(client, userdata, msg):
    topic = msg.topic
    try:
        payload = msg.payload.decode("utf-8")
    except Exception:
        return

    if topic == "zigbee2mqtt/bridge/state":
        try:
            data = json.loads(payload)
            state = data.get("state", payload)
        except json.JSONDecodeError:
            state = payload
        results["bridge_state"] = (state == "online", f"state={state}")

    elif topic == "zigbee2mqtt/bridge/info":
        try:
            data = json.loads(payload)
            coord = data.get("coordinator", {})
            fw = coord.get("meta", {}).get("revision", "unknown")
            version = data.get("version", "unknown")
            results["bridge_info"] = (True, f"z2m={version} coordinator_fw={fw}")
        except Exception as e:
            results["bridge_info"] = (False, f"parse error: {e}")

    elif topic == "zigbee2mqtt/bridge/devices":
        try:
            devices = json.loads(payload)
            total = len(devices)
            now = datetime.now(timezone.utc)
            stale = []
            for dev in devices:
                ls = dev.get("last_seen")
                name = dev.get("friendly_name", dev.get("ieee_address", "unknown"))
                dev_type = dev.get("type", "")
                if dev_type == "Coordinator":
                    continue
                if ls:
                    try:
                        last = datetime.fromisoformat(ls.replace("Z", "+00:00"))
                        hours_ago = (now - last).total_seconds() / 3600
                        if hours_ago > STALE_DEVICE_HOURS:
                            stale.append(f"{name} ({hours_ago:.1f}h ago)")
                    except Exception:
                        pass
            results["device_count"] = (total > 0, f"{total} device(s) in network")
            if stale:
                results["stale_devices"] = (
                    False,
                    f"{len(stale)} device(s) not seen in >{STALE_DEVICE_HOURS}h: "
                    + ", ".join(stale[:3]) + ("..." if len(stale) > 3 else "")
                )
            else:
                results["stale_devices"] = (True, f"All devices seen within {STALE_DEVICE_HOURS}h")
        except Exception as e:
            results["device_count"] = (False, f"parse error: {e}")
        finally:
            received.set()


print(f"=== Zigbee2MQTT Python Health Check ===")
print(f"MQTT broker: {MQTT_HOST}:{MQTT_PORT}")
print()

client = mqtt.Client(client_id="z2m-health-check")
if MQTT_USER:
    client.username_pw_set(MQTT_USER, MQTT_PASS)
client.on_connect = on_connect
client.on_message = on_message

try:
    client.connect(MQTT_HOST, MQTT_PORT, keepalive=10)
    results["mqtt_connect"] = (True, f"Connected to {MQTT_HOST}:{MQTT_PORT}")
except Exception as e:
    print(f"[FAIL] MQTT connect — {e}")
    sys.exit(1)

client.loop_start()
received.wait(timeout=SUBSCRIBE_TIMEOUT)
client.loop_stop()
client.disconnect()

# If bridge state not received, mark as failed
if "bridge_state" not in results:
    results["bridge_state"] = (False, "No message on zigbee2mqtt/bridge/state within timeout")

label_map = {
    "mqtt_connect": "MQTT connection",
    "bridge_state": "Bridge state",
    "bridge_info": "Bridge info (version/firmware)",
    "device_count": "Device count",
    "stale_devices": "Device last-seen",
}

failures = 0
for key, (ok, detail) in results.items():
    label = label_map.get(key, key)
    status = "OK" if ok else "FAIL"
    print(f"[{status}] {label} — {detail}")
    if not ok:
        failures += 1

print()
if failures == 0:
    print("Result: Zigbee2MQTT appears healthy")
    sys.exit(0)
else:
    print(f"Result: {failures} check(s) failed — review output above")
    sys.exit(1)

Common Zigbee2MQTT Outage Causes

SymptomLikely CauseResolution
Bridge offline after reboot, devices unresponsive Zigbee USB adapter not detected — udev rules missing or device path changed Add a persistent udev rule by-id; set serial.port in configuration.yaml to /dev/serial/by-id/... path instead of /dev/ttyACM0
All home automation stops responding MQTT broker disconnected or crashed, severing the bridge from all consumers Check Mosquitto/EMQX service status; verify server, user, and password in Zigbee2MQTT MQTT config; restart broker then bridge
Devices randomly dropping offline Zigbee mesh degraded — too few router devices or interference on channel 11/15/20/25 Add Zigbee router devices (IKEA plugs work well); change Zigbee channel in configuration.yaml; check for 2.4 GHz Wi-Fi channel overlap
New devices fail to pair Coordinator firmware outdated — older CC2531/CC2652 firmware has pairing limitations Flash latest coordinator firmware; use a supported adapter like Sonoff Zigbee Dongle Plus with CC2652P; check supported adapters list in z2m docs
Device history lost, entities reset in Home Assistant database.db corruption — typically caused by power loss during a write or disk full Restore from backup; set advanced.last_seen: ISO_8601 and enable regular DB backups; move DB to a non-SD-card path
Unknown devices joining the network permit_join accidentally left enabled — security risk in multi-unit buildings Set permit_join: false in configuration.yaml; use time-limited join via the frontend or API rather than leaving it open permanently

Architecture Overview

ComponentFunctionFailure Impact
Zigbee USB Coordinator Hardware radio managing the Zigbee PAN (personal area network) and mesh routing Entire Zigbee network goes offline; no device communication possible
Zigbee2MQTT Bridge Process Translates Zigbee frames to/from JSON MQTT messages; manages device registry and database All device state updates and commands stop; MQTT topics go stale
MQTT Broker (Mosquitto/EMQX) Message bus for distributing device state to Home Assistant, Node-RED, and other consumers Bridge disconnects; all subscribers lose real-time device data
database.db (SQLite) Stores device network parameters, last-seen timestamps, and scene data Device history unavailable; devices may need re-pairing after corruption
Zigbee Mesh (Router Devices) End devices relay traffic through mains-powered router nodes to the coordinator End devices out of coordinator range go offline without sufficient router coverage
Zigbee2MQTT Frontend (port 8080) Optional web dashboard for device management, OTA updates, and network map Cannot manage devices via UI; bridge continues operating normally

Uptime History

DateIncident TypeDurationImpact
2026-02 Breaking configuration schema change in Zigbee2MQTT 2.x migration Several hours per affected user Bridge refused to start after upgrade until configuration.yaml was migrated to new format
2025-10 Coordinator firmware regression with CC2652-based adapters ~12 hours New device pairing failed; existing paired devices continued operating normally
2025-08 Node.js 20 deprecation crash on older Raspberry Pi OS installs Variable (user-managed) Bridge crashed on startup after system Node.js upgrade; required manual version pin
2025-07 Widespread SD card corruption causing database.db loss Variable (user-managed) Device registry lost; all devices required re-pairing and re-configuration in Home Assistant

Monitor Zigbee2MQTT Automatically

Zigbee2MQTT failures are invisible until a light won't turn on or a motion sensor fails to trigger an alarm — by then, automation has already been broken for hours. ezmon.com monitors your Zigbee2MQTT endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the bridge state topic stops reporting "online" or the MQTT broker becomes unreachable.

Set up Zigbee2MQTT monitoring free at ezmon.com →

zigbee2mqttzigbeemqtthome-automationhome-assistantstatus-checker