Tutorials 10 min read

Zigbee2MQTT with Home Assistant in 2026: Complete Guide

Install Mosquitto, Zigbee2MQTT and Home Assistant with Docker Compose, pass the Zigbee dongle to the container, secure the MQTT broker and pair your Zigbee devices.

See our picks
S By Selfhostr Team · no sponsored content
Zigbee2MQTT with Home Assistant in 2026: Complete Guide
ⓘ ⓘ This article may contain affiliate links (no extra cost to you, it funds the site). As an Amazon Associate, Selfhostr earns from qualifying purchases. See the disclosure.
⏱️
~45 min
Duration
🎚️
Intermediate
Difficulty
💶
0 € (free software)
Cost
📦
Docker installed and configured
Key Prerequisites

👍 What we like

  • ✓Supports a large number of Zigbee devices across brands, with no proprietary hub
  • ✓Automatic device discovery in Home Assistant through MQTT
  • ✓File-based configuration that's easy to back up and reproduce
  • ✓Runs 100% locally, with no cloud

👎 What to watch

  • ✕Three services to maintain (broker, Zigbee2MQTT, Home Assistant)
  • ✕Dongle compatibility must be checked: not every chip is recommended
  • ✕Losing the network key or changing the channel means re-pairing your devices
  • ✕The Container edition of Home Assistant doesn't offer apps (add-ons)

🏆 Our picks

Affiliate links · same price for you
Recommended
Energenie EDZB1943W Zigbee USB Stick

Energenie EDZB1943W Zigbee USB Stick

Voir sur Amazon

Amazon · price and availability on the listing

Robust Mini-PC
📦

Intel NUC Kit NUC8I7HBN

Voir sur Amazon

Amazon · price and availability on the listing

See all our recommended gear in the shop.

📑 Contents ▾

This guide sets up a complete Zigbee home automation stack on a Linux server with Docker. Mosquitto is the MQTT broker, Zigbee2MQTT drives the Zigbee dongle and Home Assistant provides the interface and automations. The idea is simple. Zigbee2MQTT talks to Zigbee devices (bulbs, plugs, sensors) through the dongle and publishes their state to the MQTT broker. Home Assistant connects to that broker, not to Zigbee2MQTT, and discovers the devices automatically through MQTT discovery. Without a broker nothing works: Zigbee2MQTT won’t start and Home Assistant has nothing to integrate.

All three services run from a single Compose file. They stay reachable from your local network only.

Prerequisites

  • An up-to-date 64-bit Linux server (this guide uses Ubuntu Server 24.04 LTS) with sudo access. An x86 mini-PC such as the Intel NUC Kit NUC8I7HBN works as a Docker host. Be aware that it’s a “barebone” kit: make sure RAM and an SSD are installed.
  • A USB Zigbee adapter (coordinator). Zigbee2MQTT recommends adapters with Texas Instruments (Z-Stack), Silicon Labs (EmberZNet) or Dresden Elektronik (deCONZ) chips. The Energenie EDZB1943W Zigbee USB Stick is not on Zigbee2MQTT’s official adapter list, and we found no official spec sheet that gives its chip. Before using it, identify its chip (step 2) and check that the chip is listed at https://www.zigbee2mqtt.io/guide/adapters/. If it isn’t, pick an adapter from that list.
  • A fixed IP address on your local network (a reserved DHCP lease on your router). You do not need a domain name or any ports opened to the Internet.
  • If possible, a short USB extension cable to keep the dongle away from the server and its USB 3 ports, a known source of 2.4 GHz interference.

Step-by-step installation

Step 1: Install Docker Engine and the Compose plugin

The official script installs Docker Engine and the Compose v2 plugin (the docker compose command, with a space). Don’t install the old docker-compose v1 package, which is no longer maintained.

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Log out and back in so the group membership takes effect

Check:

docker --version
docker compose version
docker run --rm hello-world

The first two commands print a version and the third prints “Hello from Docker!”. Membership in the docker group is equivalent to root access, so only add trusted accounts.

Step 2: Identify the Zigbee dongle

Plug in the dongle, then run:

lsusb
ls -l /dev/serial/by-id/

Write down the full path, which looks like /dev/serial/by-id/usb-…-if00-port0. This path is stable, unlike /dev/ttyUSB0 or /dev/ttyACM0, which can change after a reboot. The lsusb line and the by-id link name often show the USB chip vendor. For the Zigbee chip itself, check your dongle maker’s documentation. The chip sets the adapter value in step 4: zstack (Texas Instruments), ember (Silicon Labs), deconz (ConBee/RaspBee), zigate or zboss.

Check: ls -l /dev/serial/by-id/ should list one link for your dongle. If the folder doesn’t exist, see Troubleshooting.

Step 3: Create the folder layout and configure Mosquitto

mkdir -p ~/domotique/{mosquitto/config,mosquitto/data,mosquitto/log,zigbee2mqtt/data,homeassistant/config}
cd ~/domotique
nano mosquitto/config/mosquitto.conf

Contents of mosquitto.conf:

persistence true
persistence_location /mosquitto/data/
log_dest stdout

listener 1883
allow_anonymous false
password_file /mosquitto/config/passwd

Since version 2.0, Mosquitto requires you to choose an authentication method explicitly. Here, anonymous connections are refused. Now create two accounts, one for Zigbee2MQTT and one for Home Assistant (you’ll be prompted for each password):

docker run --rm -it -v "$PWD/mosquitto/config:/mosquitto/config" eclipse-mosquitto:2 \
  mosquitto_passwd -c /mosquitto/config/passwd zigbee2mqtt
docker run --rm -it -v "$PWD/mosquitto/config:/mosquitto/config" eclipse-mosquitto:2 \
  mosquitto_passwd /mosquitto/config/passwd homeassistant

Use -c for the first command only, because it overwrites an existing file.

Check:

cat mosquitto/config/passwd

You should see two lines, zigbee2mqtt:$7$… and homeassistant:$7$…, with hashed passwords rather than plain text.

Step 4: Write the Zigbee2MQTT configuration

First, generate a token to protect the web interface:

openssl rand -hex 32
nano ~/domotique/zigbee2mqtt/data/configuration.yaml
version: 5
homeassistant:
  enabled: true
frontend:
  enabled: true
  port: 8080
  auth_token: PASTE_THE_GENERATED_TOKEN_HERE
mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://mosquitto:1883
  user: zigbee2mqtt
  password: ZIGBEE2MQTT_ACCOUNT_PASSWORD
serial:
  port: /dev/ttyACM0
  adapter: ember   # replace to match your chip: zstack, ember, deconz, zigate or zboss
advanced:
  channel: 11
  network_key: GENERATE
  pan_id: GENERATE
  ext_pan_id: GENERATE

A few things to know:

  • mqtt and serial are top-level sections (there is no bridge key). mosquitto is the service name in the step 5 Compose file.
  • serial.port is the path inside the container. The Compose file maps the host’s by-id path to it.
  • version: 5 follows the current documentation example. If your image is older, check the expected value in the documentation for your version.
  • On first start, GENERATE is replaced with random keys. Back up this file: if you lose the network_key, you’ll have to re-pair every device.
  • Changing the channel later means re-pairing your devices. The documentation advises choosing a channel away from your 2.4 GHz Wi-Fi channel.
  • You don’t write the devices: section yourself. Zigbee2MQTT fills it in as you pair devices, as a map keyed by each device’s IEEE address (for example '0x00158d0001234567': friendly_name: living_room_sensor). The coordinator is never listed there.
chmod 600 ~/domotique/zigbee2mqtt/data/configuration.yaml

Check: python3 -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" ~/domotique/zigbee2mqtt/data/configuration.yaml should print no error. If the module is missing, install it with sudo apt install python3-yaml.

Step 5: Create the compose.yaml file

nano ~/domotique/compose.yaml
services:
  mosquitto:
    image: eclipse-mosquitto:2
    container_name: mosquitto
    restart: unless-stopped
    ports:
      - "127.0.0.1:1883:1883"   # reachable from the host only
    volumes:
      - ./mosquitto/config:/mosquitto/config
      - ./mosquitto/data:/mosquitto/data
      - ./mosquitto/log:/mosquitto/log

  zigbee2mqtt:
    image: ghcr.io/koenkk/zigbee2mqtt
    container_name: zigbee2mqtt
    restart: unless-stopped
    depends_on:
      - mosquitto
    ports:
      - "8080:8080"   # web interface
    volumes:
      - ./zigbee2mqtt/data:/app/data
      - /run/udev:/run/udev:ro
    environment:
      - TZ=Europe/Paris
    devices:
      - /dev/serial/by-id/REPLACE_WITH_YOUR_DONGLE:/dev/ttyACM0

  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    network_mode: host
    privileged: true
    volumes:
      - ./homeassistant/config:/config
      - /etc/localtime:/etc/localtime:ro
      - /run/dbus:/run/dbus:ro
    environment:
      - TZ=Europe/Paris

There’s no version: key (obsolete) and no docker-compose: key. The whole Zigbee2MQTT data folder is mounted at /app/data, so the configuration, device database and state persist. Home Assistant runs with network_mode: host, as in the official documentation, so it reaches Mosquitto at 127.0.0.1:1883. Zigbee2MQTT reaches it over the internal Compose network (mosquitto:1883).

Check:

cd ~/domotique && docker compose config --quiet && echo OK

Step 6: Start the stack

docker compose up -d
docker compose ps
docker compose logs -f zigbee2mqtt

Check: all three containers are running (or Up). The Zigbee2MQTT logs should show the connection to the MQTT server and then the startup message (Zigbee2MQTT started!), with no serial port error. Exit with Ctrl+C. Next, check the broker:

docker compose exec mosquitto mosquitto_sub -h localhost -u homeassistant -P 'HA_PASSWORD' \
  -t 'zigbee2mqtt/bridge/state' -C 1 -v

The expected output is zigbee2mqtt/bridge/state {"state":"online"}. Finally, open http://SERVER_IP:8080 and enter the auth_token: the Zigbee2MQTT interface appears.

Step 7: Set up Home Assistant and the MQTT integration

  1. Open http://SERVER_IP:8123 and create the owner account.
  2. Go to Settings > Devices & services, click Add Integration (bottom right) and choose MQTT.
  3. Enter the broker details: host 127.0.0.1, port 1883, user homeassistant and its password.

The default discovery prefix, homeassistant, matches what Zigbee2MQTT uses with homeassistant: enabled: true. Leave it unchanged.

Check: under Settings > Devices & services, the MQTT integration shows no error, and a “Zigbee2MQTT Bridge” device is listed among its devices.

Step 8: Pair Zigbee devices

In the Zigbee2MQTT interface (port 8080), click the Permit join button at the top of the page. Joining is temporary and stops on its own when the countdown ends. Then put the device into pairing mode as its manual describes: reset, long press, and so on. Pair it close to the dongle or to a Zigbee router (usually a mains-powered device).

Check: the device appears in the Devices tab with its model recognised. The logs show that the “interview” completed successfully. In Home Assistant, the device and its entities appear under the MQTT integration. Give it a meaningful name in Zigbee2MQTT before you build automations.

Step 9: Create a first automation

In Home Assistant, go to Settings > Automations & scenes > Create automation. For example: a “Device” trigger using your motion sensor, an optional condition, and a “Device” action that turns on your bulb.

Check: trigger the sensor. The automation’s trace, in the automation’s ⋮ menu, shows the run and the bulb turns on.

Verification checks

cd ~/domotique
docker compose ps                                   # 3 services running
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080   # expect 200
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8123   # expect 200
docker compose logs --tail 50 zigbee2mqtt | grep -i error       # ideally empty

Other checks: the Map tab in Zigbee2MQTT shows the network mesh. In Home Assistant, your devices’ entities should change state when you operate them.

Security and best practices

  • Nothing is exposed to the Internet. Don’t forward ports 1883, 8080 or 8123 on your router. For remote access, use a VPN (WireGuard, for example).
  • Here, Mosquitto listens on 127.0.0.1 only. If other clients on your LAN need to connect, publish the port on the server’s LAN IP ("192.168.1.10:1883:1883") and keep authentication on. Ports published by Docker bypass UFW rules, so don’t rely on the host firewall to filter them.
  • Keep the auth_token on the Zigbee2MQTT interface and use separate MQTT passwords for each client. configuration.yaml holds secrets in plain text, hence the chmod 600.
  • Backups: back up all of ~/domotique/ regularly, especially zigbee2mqtt/data (configuration, network keys, device database) and homeassistant/config.
  • Updates: read the release notes, then run docker compose pull && docker compose up -d. Avoid unattended automatic updates.

Troubleshooting common errors

  • Symptom: Zigbee2MQTT stops with an error opening the serial port.
    • Cause: wrong by-id path under devices:, the dongle is in use by another service (the ZHA integration, for example) or the adapter value is wrong.
    • Fix: check ls -l /dev/serial/by-id/, correct compose.yaml and adapter, then restart with docker compose up -d. Only one program can use a dongle at a time.
  • Symptom: /dev/serial/by-id/ doesn’t exist on Ubuntu.
    • Cause: the brltty service (braille displays) sometimes grabs dongles with CH340/CH341 USB chips.
    • Fix: check with sudo dmesg | grep -i -E 'tty|brltty'. If you don’t use a braille display, remove it with sudo apt remove brltty and re-plug the dongle.
  • Symptom: Connection refused or Not authorized in the MQTT logs.
    • Cause: wrong credentials or a missing passwd file.
    • Fix: check docker compose logs mosquitto, recreate the account with mosquitto_passwd (without -c), then run docker compose restart mosquitto.
  • Symptom: pairing fails.
    • Cause: Permit join is off, the device is too far away, or there’s Wi-Fi or USB 3 interference.
    • Fix: turn Permit join back on, move the device closer, use a USB extension cable and check that the device is on the supported devices list.
  • Symptom: Home Assistant doesn’t see the devices.
    • Cause: the integration points to the wrong host, or discovery is disabled.
    • Fix: the integration must point to the broker (127.0.0.1:1883), and homeassistant: enabled: true must be set in the Zigbee2MQTT configuration.

FAQ

Is the configuration.yaml file mandatory?

Yes. Zigbee2MQTT reads its settings from data/configuration.yaml. Recent versions may offer a web onboarding wizard on first start if the file is missing (check the documentation for your version), but the wizard produces the same file. Writing it yourself, as in step 4, makes the setup reproducible.

Which Zigbee devices are supported?

See the official “Supported devices” list at https://www.zigbee2mqtt.io/supported-devices/. It’s generated from the zigbee-herdsman-converters project and shows the features exposed for each model.

How do I update Home Assistant?

With Docker, you update by pulling a new image: docker compose pull homeassistant && docker compose up -d homeassistant. HACS has nothing to do with this: it installs community integrations and cards, not Home Assistant updates.

What if I use Home Assistant OS?

Home Assistant OS lets you install Mosquitto and Zigbee2MQTT as apps (formerly “add-ons”) from its interface. The logic is the same: MQTT broker, Zigbee2MQTT, then the MQTT integration. This guide covers the “Container” installation under Docker, which doesn’t offer those apps.

Can I use ZHA and Zigbee2MQTT at the same time?

Not with the same dongle. Pick one, or use a second coordinator on another channel.

Read also

Host this yourself

No hardware to manage? This kind of service runs on a managed VPS, ready in minutes. See PlanetHoster plans

Tags: zigbeehomeassistantmqttselfhostingtutorial

Related

Tutorials

Home Assistant on Mini-PC in 2026: Zigbee Key and Backups

Install Home Assistant Container with Docker Compose on a Linux mini-PC, add a ConBee III stick through ZHA, and set up encrypted automatic backups, local HTTPS with Caddy and two-factor authentication.

Read
Tutorials

Frigate + Google Coral with Home Assistant in 2026

Install Frigate with a Coral Edge TPU (USB or PCIe) in Docker, configure the edgetpu detector, MQTT and the Frigate integration via HACS in Home Assistant, without exposing Frigate to the Internet.

Read
Tutorials

Automate the opening of a connected garage with Home Assistant in 2026

Connect a motorized garage door to Home Assistant: a Zigbee contact sensor to know its state, a relay module to operate it, and careful automations (alert when it stays open, light at night).

Read