private@homelab: ~/latest
local-first guides · privacy-aware · no noisy tracking
private@homelab:~$ cat guides/article.md
·
· ·
8–12 minutes
read

ZHA to Zigbee2MQTT Migration: Re-Pair or Convert DB

Migrating from ZHA to Zigbee2MQTT: the reliable re-pair method, the two-part no-re-pair shortcut, and how to sequence it without losing your mesh. Stays local.

Migrating from ZHA to Zigbee2MQTT is a decision a lot of Home Assistant users eventually face, usually because Z2M’s broader third-party device support or its external-converter ecosystem solves a problem ZHA can’t. The question that stalls people isn’t whether to switch. It’s whether every device has to be re-paired from scratch, or whether the existing network can carry over.

There are two real answers, and they trade off against each other. A clean re-pair is the reliable default. It’s slower for a large network, but it’s the path the Zigbee2MQTT maintainers themselves describe. The no-re-pair route is the shortcut, and it turns out to be two jobs rather than one: Zigbee2MQTT has to be handed ZHA’s network credentials, and it has to be handed a record of the devices on that network. Both parts carry real risk that the tooling’s own author is upfront about. This piece lays out both methods, in what order to do things, and which one fits which situation. It’s research-synthesis from the Zigbee2MQTT maintainer discussions, the conversion tool’s own documentation, and community migration reports, not a migration this site has run on its own hardware.

Either way, nothing here leaves your local network. This is a move between two local-only Zigbee integrations on the same Home Assistant instance, with no cloud account, vendor app, or external service involved at any point.

Why migrate from ZHA to Zigbee2MQTT (and why it isn’t a hardware swap)

The most common reason people move is device support. Zigbee2MQTT’s external-converter system and its faster community response to new devices mean it sometimes supports hardware ZHA doesn’t yet, or supports it with fewer manual workarounds. Our guide to writing a custom ZHA quirk covers what it takes to add support for an unsupported device on the ZHA side, for readers weighing “write a quirk” against “just switch platforms.”

This is not the same operation as moving your Zigbee network to new coordinator hardware while staying on the same integration platform. A Zigbee coordinator either is the controller of a given network, or it isn’t. It can’t “join” another network the way an end device can, so replacing a coordinator dongle and keeping ZHA (or keeping Z2M) is a hardware-level operation with its own procedure. Switching between ZHA and Zigbee2MQTT on the same coordinator is an integration-level operation, and the two get conflated constantly in forum threads because both get called “migration.” If your actual goal is new coordinator hardware, our ZBDongle-E vs ZBDongle-P comparison and coordinator firmware update guide are the more relevant starting points. If you’re still deciding whether ZHA or Zigbee2MQTT is the right platform at all, ZHA vs Zigbee2MQTT for Aqara devices is the companion piece.

Method 1: the reliable default, a clean re-pair

The method described directly by a Zigbee2MQTT maintainer in the project’s own migration discussion is a fresh start. Install Zigbee2MQTT, generate a new PAN ID and network key rather than reusing ZHA’s, and treat this as the natural point to also pick a better channel if your current one is congested. The reasoning is worth understanding: a new network key forces a re-pair anyway, so the channel improvement is effectively free once you’ve committed to that cost.

configuration.yaml
advanced:
  pan_id: GENERATE
  network_key: GENERATE
  channel: 20

From there, re-pair in a specific order rather than whatever’s convenient. Pair mains-powered router devices first, since they rebuild the mesh backbone everything else relies on, then other mains-powered devices, then battery-powered devices last (wake them, then pair). Pairing battery devices before the mesh has routers in place tends to leave them stuck routing through the coordinator directly, which is exactly the fragile setup a mesh is supposed to avoid.

Note · before you start

This is a same-coordinator, same-radio operation. You are replacing the software controlling that hardware, not the hardware itself.

What a clean re-pair costs you

The re-pair method is reliable, but it isn’t free. Device-side customizations, most obviously friendly names, don’t carry over. Whatever naming scheme you had in ZHA has to be rebuilt in Zigbee2MQTT from scratch.

The more consequential cost is that any automation, script, or dashboard entity referencing those devices needs to be repointed once the entities are recreated under Zigbee2MQTT. For a handful of devices this is an afternoon’s work. For a network with 60 or 80 devices and years of accumulated automations, it’s the reason people go looking for an alternative in the first place.

Method 2: carrying the network over instead of re-pairing

The shortcut has two halves, and most write-ups only describe one of them.

The first half is the Zigbee network itself. A separate maintainer discussion on migration network keys covers reading the PAN ID, extended PAN ID, network key and channel out of ZHA’s network configuration and writing those same values into Zigbee2MQTT, so the new software comes up on the network your devices are already joined to rather than forming a fresh one. Get this part wrong and nothing else matters: Zigbee2MQTT starts a network of its own, and every device record you carefully converted points at a device it can’t reach.

The formats aren’t interchangeable, which is the practical trap. Zigbee2MQTT expects the network key as an array of decimal bytes and the extended PAN ID as an array of hex bytes, while ZHA presents both as hex strings. The values have to be converted, not pasted across.

configuration.yaml (Method 2)
advanced:
  pan_id: 6754
  ext_pan_id: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]
  network_key: [12, 34, 56, 78, 90, 21, 43, 65, 87, 9, 10, 11, 13, 14, 15, 16]
  channel: 15

Those are placeholder values in the right shape. Yours come out of your own ZHA network settings, and the channel has to match whatever ZHA is already using rather than one you’d prefer.

The second half is Zigbee2MQTT’s own record of what’s on that network. A community-maintained tool, mietzen/zha-to-z2m, automates this part: it extracts device data from ZHA’s zigbee.db and appends it into Zigbee2MQTT’s database.db. Our guide to a corrupted or wiped database.db covers what that same file looks like when something goes wrong with it outside a migration context, which is useful background before touching it directly.

Even with both halves done, each device still needs to be interviewed afterward so Zigbee2MQTT can populate its own definition of what that device exposes, in the same router-first order as a clean re-pair. The conversion moves the bookkeeping over. It doesn’t skip Z2M getting to know each device on its own terms.

Warning

The tool’s own README warns against attempting this when you’re in a hurry, states that a failed run can destroy your existing ZHA setup, and notes that it only works unmodified against certain Home Assistant configurations. Back up zigbee.db, your Zigbee2MQTT database.db, and your ZHA network settings before running it, and don’t start an hour before you need the network working.

How much confidence to put in this: one detailed community report describes migrating successfully without re-pairing. That’s a specific, documented outcome rather than a rumour, but it’s one case, not a success rate. No tool version and no proportion of successful runs is confirmed anywhere, so treat this as a technique that has worked for someone, not a supported procedure.

Sequencing: don’t tear down ZHA too early

The same documented report is specific about ordering, and it’s the part people skip when they’re eager to finish. Don’t dismantle the ZHA side until Zigbee2MQTT is confirmed running correctly against the converted data. Leave the integration configured, leave zigbee.db where it is, and keep your backups.

Warning

Removing the ZHA integration before Zigbee2MQTT is confirmed working leaves you with no fallback if the converted network doesn’t behave the way you expect. Confirm devices are reporting correctly in Zigbee2MQTT first, then remove ZHA.

I think this sequencing rule is the single most important line in the whole no-re-pair approach, more so than the conversion mechanics themselves, because it’s the difference between “worst case, I redo the re-pair” and “worst case, I have no working Zigbee network at all.”

Which method fits your situation

Situation Method Why
Under ~20 devices, few automations Clean re-pair The rebuild work is small enough that reliability wins outright
Large network, heavy automation dependency, comfortable with backups Network carry-over plus database conversion Re-pairing everything and rebuilding automations is genuinely painful at this scale, and a two-part procedure is the price of avoiding it
Any network, no recent backup taken Clean re-pair Don’t attempt the carry-over without a backup you’ve verified you can restore
Time-pressured, need the network working today Clean re-pair The tool’s own author warns against running the conversion when rushed

FAQ

Can I migrate from ZHA to Zigbee2MQTT without re-pairing every device?

Yes, in principle, but it takes two things rather than one: Zigbee2MQTT configured with ZHA’s PAN ID, extended PAN ID, network key and channel, plus a record of your devices carried into its database. Each device still gets interviewed afterward. Treat it as an advanced option with a real failure mode, not a guaranteed-safe default.

Will I lose my device names and automations when migrating?

With a clean re-pair, yes. Friendly names and any automations referencing the old ZHA entities need to be rebuilt or repointed. The carry-over approach is specifically aimed at avoiding this.

Do I need a new Zigbee coordinator to switch from ZHA to Zigbee2MQTT?

No. This is a software-integration change on the same coordinator hardware, not a hardware migration. Moving to different coordinator hardware entirely is a separate operation with its own considerations, covered in our ZBDongle-E vs ZBDongle-P comparison.

What’s the safest order to re-pair devices when migrating?

Mains-powered router devices first, since they form the mesh backbone, then other mains-powered devices, then battery-powered devices last.

Can I run ZHA and Zigbee2MQTT at the same time during migration?

Not against the same coordinator. One client holds the adapter’s serial connection, so the two integrations take turns rather than running side by side. What the documented report describes is a sequencing safeguard rather than concurrent operation: keep the ZHA side intact, integration still configured and zigbee.db untouched, so you can go back to it, and take it down only once Zigbee2MQTT is confirmed working. Running two coordinators, one per integration on two separate Zigbee networks, is a different setup and outside what these migration sources cover.

What this piece verified

This article is built from the Zigbee2MQTT maintainer discussions on migration and on migration network keys, the mietzen/zha-to-z2m README’s own description and warnings, and one detailed community report of a migration done without re-pairing, all cited inline. No re-pair and no database conversion was run against hardware for this piece.

What those sources support: the clean re-pair procedure and its device order; the maintainer recommendation to generate a fresh PAN ID and network key rather than reuse ZHA’s; the network parameters and formats Zigbee2MQTT needs if you do reuse them; what the conversion tool does and what its author warns it can break; and the sequencing rule from the single documented success report.

What no source establishes, and what this piece therefore doesn’t claim: how often the conversion works, which tool version to run, or whether your particular device set will interview cleanly afterward. Take backups of both the database and your network settings before starting either method, and confirm the new setup is stable before you remove the old integration.

local-firstHome Assistantno-cloud