Tech Digest

Home automation

Zigbee2MQTT

Bridges a USB Zigbee radio to MQTT so your sensors stop needing vendor hubs

Home automationGPL-3.0Maturearm64 builds
Last reviewed Profile maintained against the project's own documentation
Operational load
2 / 5
Light
Idle memory
90 MB
typical use ~220 MB
Moving parts
2
containers in a normal deployment
Backup shape
File copy
live file copy safe

Zigbee2MQTT drives a USB or Ethernet Zigbee coordinator and publishes every device as MQTT topics, with a web frontend for pairing, binding, OTA firmware and a live network map. It replaces the Hue Bridge, the Aqara hub and the SmartThings hub, letting devices from different vendors sit on one Zigbee mesh you control.

Our verdict on Zigbee2MQTT#

Zigbee2MQTT is well into the 2.x line (2.14.1 shipped on 3 September 2026), and the 2.0 jump was the real break: the legacy MQTT API is gone, permit_join can no longer be set in configuration.yaml, and on first start it rewrites your config and records what it stripped in migration-1-to-2.log. Two decisions matter more than the software. Buy a coordinator from the supported list, a CC2652 based stick or an EmberZNet one, and check its firmware before you pair forty devices, because swapping coordinator families later normally means re-pairing everything. Then choose your channel on purpose. The default is 11, which sits underneath Wi-Fi channel 1. The docs recommend the ZLL channels 11, 15, 20 or 25; if your Wi-Fi is on 1, 6 and 11, then Zigbee 15, 20 or 25 give you the quiet gaps. Changing channel afterwards drops the devices that ignore the announcement.

Who Zigbee2MQTT is for#

Choose it if

  • Anyone with Zigbee devices from three vendors who is tired of running three vendor bridges
  • People who want cheap Aqara and Sonoff sensors reporting locally with no account and no cloud outage
  • Home Assistant users who prefer MQTT they can inspect over an opaque built-in integration
  • Anyone who wants device binding and group control that keeps working when the hub is rebooting

Look elsewhere if

  • You only own a handful of Hue bulbs and are happy with the Hue Bridge, which does local control fine
  • You cannot put the coordinator on a USB extension away from the machine, because on-board it will be deaf
  • You want a supported appliance; coordinator firmware flashing and channel planning are yours to own

What running it actually looks like#

Two containers in practice: Zigbee2MQTT and an MQTT broker, usually Mosquitto, which has to be up before it starts or it exits. Run ghcr.io/koenkk/zigbee2mqtt with the data directory mounted at /app/data, the frontend on 8080, and the coordinator passed through as --device=/dev/serial/by-id/usb-...:/dev/ttyACM0. Use the by-id path, never /dev/ttyUSB0, and mount /run/udev:ro so adapter discovery works. Official images cover amd64, arm64 and armv6/v7. First run is empty until you press the join button in the frontend, which opens the network for 254 seconds; pairing is deliberately not a config setting any more. Upgrades are a tag bump, except across the 1.x to 2.x boundary, which rewrites your config file in place.

Resource profile#

Memory
90 MB idle, around 220 MB in ordinary use. A single Node process. Memory tracks device count and logging level more than traffic; a 60 device network settles around 150 to 250 MB.
CPU and acceleration
Effectively zero in steady state; it is a serial port to MQTT translator. Startup re-reads the device database and can hold one core busy for a minute, and OTA firmware pushes to a device are slow but cheap.
Storage growth
Tiny. The data directory is a few MB of configuration.yaml, database.db, coordinator_backup.json and state.json. Only the log directory grows, and it will run away if you leave log_level at debug with no rotation.
Operational load
2 of 5, Light. One container plus an MQTT broker, config is a single YAML file, and backup is copying the data directory. Upgrades are usually uneventful, but coordinator firmware and the 1.x to 2.x migration are the two moments that need reading first.

Figures describe a small single-household install and are the working assumptions behind our stack planner. Your numbers will differ with library size, user count and hardware. See methodology.

Data and backup surface#

Back up the whole data directory: configuration.yaml holds your MQTT settings, the network_key, pan_id and ext_pan_id; database.db is the device list and their attributes; coordinator_backup.json lets a replacement stick adopt the same network. A live copy is fine for a scare, but stop the container for a clean one, because database.db is rewritten as devices report. Nothing here is regenerable in any useful sense: lose the network key and every device has to be re-paired by hand, one press of a tiny reset pin at a time. Exclude the log/ directory. The whole thing is a few MB, so version it.

Derived backup shape

File copy. Copy the config and data directories. Safe while running for anything that writes atomically.

Traps and surprises#

The 1.x to 2.x config migration is one-way

On first start, 2.0 rewrites configuration.yaml, deletes settings like availability_timeout and legacy_api, and logs the changes to migration-1-to-2.log in the data directory. There is no revert. Copy the data directory before you pull the new tag. The same release also removed the legacy MQTT API endpoints for bind, group, networkmap and ota_update, so any script or dashboard built on those topics stops working silently.

Zigbee and Wi-Fi share 2.4 GHz and Wi-Fi wins

Zigbee channel 11 (the default) overlaps Wi-Fi channel 1, and 802.11 transmits far louder. If your access point sits on Wi-Fi 1, 6 or 11, move Zigbee to 15, 20 or 25. Symptoms of a bad choice are battery sensors that report intermittently and lights that respond after two seconds, not total failure, which is why people live with it for months. Changing channel later can require re-pairing devices that miss the change.

USB 3.0 ports and enclosures deafen the coordinator

A Zigbee stick plugged directly into a USB 3 port, or next to an external SSD, sits in a wall of broadband noise at 2.4 GHz. Range collapses to a few meters and you will blame the mesh. Use a one meter USB 2.0 extension cable, get the stick away from the host and any metal rack, and only then judge coverage. This is the single most common cause of a mesh that works next to the server and nowhere else.

network_key and pan_id are unrecoverable

Set them to GENERATE once and never touch them again. Changing the network key or the PAN ID forces every device on the mesh to be re-paired, and battery devices usually need a physical reset sequence to do it. Keep configuration.yaml in your backups for this reason alone, and if you keep the config in git, use the secrets file so the key does not end up in a repository.

Swapping coordinators usually means re-pairing

Moving between adapter families (zStack to EmberZNet, say) means the network does not follow. Within a family you can carry it over by writing the old adapter's IEEE address onto the new one and restoring coordinator_backup.json. Only zStack and EmberZNet adapters support coordinator backups at all, which is a good reason to avoid the others. If you do want to start fresh, delete both database.db and coordinator_backup.json first.

Specifications#

Category
Home automation
Licence
GPL-3.0 (Copyleft)
Written in
TypeScript / Node.js
First release
2018
Maturity
Mature
Datastore
Flat files in the data directory (database.db, a JSON lines file)
Default ports
8080
Ships as
docker, home assistant app, npm / node
arm64 builds
Yes
Identity
Local accounts only. The frontend has one shared `auth_token` in configuration.yaml, no user accounts and no OIDC, so put a proxy in front if it leaves your LAN.
Replaces
Philips Hue Bridge, Aqara Hub, SmartThings Hub, IKEA Dirigera
Project site
www.zigbee2mqtt.io
Source
github.com/Koenkk/zigbee2mqtt
Documentation
www.zigbee2mqtt.io/guide/getting-started

Alternatives to Zigbee2MQTT#

Everything else in home automation, closest in operational weight first.

ToolOps loadIdle RAMLicence
ESPHome2, Light150 MBMIT (Python tooling) and GPL-3.0 (C++ device runtime)
Node-RED2, Light110 MBApache-2.0
Frigate3, Moderate700 MBMIT
Home Assistant4, Heavy600 MBApache-2.0

Where Zigbee2MQTT comes up elsewhere#

Sources#

Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.