ZHA vs Zigbee2MQTT: Differences and Tradeoffs
This comparison explains how ZHA and Zigbee2MQTT differ in setup, device support, interfaces, MQTT requirements, migration, and best-fit use cases.
The short version of ZHA vs Zigbee2MQTT explained: both turn a USB coordinator into a Zigbee network for Home Assistant, both run on the same sticks, and the real difference is where the software lives. ZHA is an integration inside Home Assistant, built on the zigpy stack. Zigbee2MQTT is a separate program that publishes everything to an MQTT broker, and Home Assistant picks the devices up from there. That one choice explains nearly every argument about the two: the extra add-on, the bigger device list, the separate web UI, and why switching means moving the whole network.
What the two actually are
The ZHA documentation describes it as “a hardware-independent Zigbee gateway implementation that can replace most proprietary Zigbee gateways”. It ships with Home Assistant, is set up from Settings > Devices & services, and needs nothing else running. It supports five radio families: EZSP (Silicon Labs EmberZNet), ZNP (Texas Instruments), deCONZ, ZiGate and XBee.
Zigbee2MQTT calls itself a “Zigbee to MQTT bridge”. It runs as its own process, and Home Assistant learns about devices through MQTT discovery. The integration page needs homeassistant: enabled: true in Zigbee2MQTT’s configuration plus the MQTT integration on the Home Assistant side. Once discovered, devices land in the normal device registry and you can change entity_id and friendly_name from the Home Assistant UI “without having to restart Home Assistant”. On Home Assistant OS it installs as an add-on; the add-on page supports only aarch64 and amd64 and asks for at least a Raspberry Pi 4. On a Container install it runs in Docker against your own broker, as covered in how to add Zigbee2MQTT to Home Assistant.
The MQTT broker is Zigbee2MQTT’s first real cost: one more service to install, back up and keep running. It is also a feature, because every device event lands on a bus that Node-RED and other tools can read directly.
Same sticks, different drivers
The Zigbee2MQTT adapters page recommends three families, zStack (Texas Instruments), EmberZNet (Silicon Labs) and deCONZ, and marks ZiGate “not maintained” and ZBOSS “experimental”. ZHA runs the same three plus ZiGate and XBee. Its docs call the Home Assistant Connect ZBT-2 “the one to get” for a new network, list the CC2530, CC2531 and CC2538 as “no longer recommended” because they only run deprecated firmware, and put the ConBee II and RaspBee II in the not-recommended column. The ZBT-2 pairs a Silicon Labs MG24 radio with an ESP32-S3 USB bridge, works with both ZHA and Zigbee2MQTT, and “cannot do both Zigbee and Thread simultaneously”, so plan a second stick if Thread is on the roadmap. Matterhomelab’s Thread vs Zigbee comparison covers why the two meshes stay separate.
One rule both projects state in almost the same words: a coordinator serves one application. ZHA’s docs say the coordinator “cannot already be connected or used by any other application”, and the Zigbee2MQTT FAQ says each instance “only supports connecting a single dedicated Zigbee Coordinator radio adapter or module with a single Zigbee network”.
Device support: quirks versus converters
This is where the two diverge most. ZHA speaks standard Zigbee Cluster Library to any compliant device. When a manufacturer deviates from the spec, ZHA needs a quirk. The ZHA Device Handlers project describes them as “custom quirks implementations for Zigpy” that “bridge the functionality gap created when manufacturers deviate from the ZCL specification”. They are Python files, and the ZHA docs are candid that filing a device support request “does not guarantee that someone will develop a custom quirk”.
Zigbee2MQTT takes the opposite approach: every device has a definition in zigbee-herdsman-converters, whether standard or not. The supported devices page currently lists 5592 devices from 582 vendors. For something unlisted, you pair it, open the device’s Dev console, press Generate external definition, and load the result as an external converter either from a file or over the MQTT API at runtime, then submit it upstream. That loop is why Tuya-derived and no-name gear tends to appear in Zigbee2MQTT first, and why a home full of IKEA, Hue, SONOFF and Aqara rarely notices the difference. A poster in the Home Assistant Community thread on the subject put it plainly: “Z2M also typically exposes more functionality than ZHA”.
What each UI gives you
ZHA has grown most of what people once switched for. Its docs describe a network visualization with RSSI and LQI to “identify devices with poor connection”, groups of two or more lights, switches or fans, and binding, where commands bypass ZHA and go device to device. OTA updates are “enabled by default”, surface as update notifications, and are switched on out of the box for IKEA, Inovelli, Ledvance/OSRAM, Sonoff/iTead and Third Reality; other manufacturers are supported but off “because their updates may change or remove device functionality”.
Zigbee2MQTT has a built-in web frontend on port 8080, forced to 8099 under the add-on for Home Assistant ingress, with the network map, per-device settings, logs and permit join in one place. Its OTA page pulls firmware from the Koenkk/zigbee-OTA index, warns that an update takes “10-100 minutes depending on device, settings and network stability”, and asks for 70 percent battery or better on battery devices. Group discovery covers lights, switches, locks and covers.
Switching: what moves and what does not
Both stacks implement the Open Coordinator Backup format, a “hardware-independent non-proprietary open standard” adopted by zigpy and zigbee-herdsman so users can migrate “between coordinator hardware and network management software without having to needlessly rejoin all of their devices”. The network itself is portable. The layer on top is not.
Nabu Casa’s migration guide spells out the Zigbee2MQTT to ZHA direction: download the Zigbee2MQTT backup, unzip it to get coordinator_backup.json, stop the add-on, add ZHA, and choose Upload a manual backup in the network formation dialog. Devices then rejoin on their own; the guide says “Normally, they join within one hour” and that power-cycling them can speed it up. The caveats matter more than the steps: “device names will be lost” and “all migrated devices have new entity IDs”, so every automation and dashboard card gets re-pointed. Going the other way, the Zigbee2MQTT FAQ supports backup and restore only on zstack and ember adapters, and ZHA’s automatic migration only accepts a backup “made from inside ZHA”. Budget an evening either way.
Do not switch to fix a flaky mesh. As one reply in the community thread notes, “Z2M isn’t fixing any mesh issues”; people usually change the coordinator position, channel or router count at the same time and credit the software. Work through Zigbee devices going unavailable first.
Quick reference
| ZHA | Zigbee2MQTT | |
|---|---|---|
| Runs as | Home Assistant integration | Separate service (add-on or Docker) |
| Needs MQTT | No | Yes |
| Device library | Standard ZCL plus quirks | Per-device converters, 5592 listed |
| Unsupported device | Write or request a quirk | Generate an external definition |
| UI | Home Assistant device pages | Own frontend, port 8080 or 8099 |
| Add-on host | Wherever Home Assistant runs | 64-bit only, Pi 4 or better |
| Backup format | Open Coordinator Backup | Open Coordinator Backup |
Which one to run
Pick ZHA if you are new, run Home Assistant OS, buy mainstream brands and want the fewest moving parts. Pick Zigbee2MQTT if you buy unusual Zigbee gear, want the widest definition library and a diagnostic UI, or already run an MQTT broker for other reasons. On Home Assistant Container, Zigbee2MQTT in Docker slots in naturally; Docker Homelab’s compose guide covers the bind-mount and restart-policy habits it relies on. If you are already stable on either, stay there; the migration cost is real and the feature gap has narrowed. Not settled on Zigbee at all? See Zigbee vs Z-Wave vs Thread.
Related across the network
- Matter vs Zigbee vs Z-Wave: Which One to Build a Home On — matterhomelab.com
- Thread vs Zigbee: How the Two Meshes Differ — matterhomelab.com
- Does Matter Work Without Internet? What Stays Local and What Breaks — matterhomelab.com
- How Many Thread Border Routers Do I Need? A Count by House Size and Ecosystem — matterhomelab.com
- How Matter, Thread and Border Routers Fit Together — matterhomelab.com
Sources
- Zigbee Home Automation (Home Assistant Documentation)
- FAQ (Zigbee2MQTT Documentation)
- Supported devices (Zigbee2MQTT Documentation)
- Supported adapters (Zigbee2MQTT Documentation)
- Home Assistant integration (Zigbee2MQTT Documentation)
- Home Assistant add-on installation (Zigbee2MQTT Documentation)
- OTA updates (Zigbee2MQTT Documentation)
- Frontend (Zigbee2MQTT Documentation)
- ZHA Device Handlers (zigpy on GitHub)
- zigbee-herdsman-converters (Koenkk on GitHub)
- Open Coordinator Backup format (zigpy on GitHub)
- Migrating a Zigbee2MQTT network from a backup file to Connect ZBT-1 using ZHA (Nabu Casa Support)
- Home Assistant Connect ZBT-2
- ZHA vs Zigbee2MQTT: Pros 'n Cons for conversion (Home Assistant Community)
Related
How to Add Zigbee2MQTT to Home Assistant
This guide explains Zigbee2MQTT setup in Home Assistant, including Mosquitto, the add-on, adapter setup, MQTT discovery, and pairing the first device.
Best Zigbee Coordinator Stick for Home Assistant: 4 Picks
Home Assistant Connect ZBT-2 suits ZHA, while SONOFF and SMLIGHT coordinators offer options for Zigbee2MQTT, Docker, and difficult server locations.
Zigbee Devices Going Unavailable: How to Fix It
Zigbee devices dropping offline are usually a mesh or interference fault, not a broken device. Work the documented causes in the order that pays off.