Install Zigbee2MQTT
Install Mosquitto, configure a Zigbee USB coordinator, run Zigbee2MQTT as a systemd service, and pair devices using the built-in web frontend.
Before you start
- ▸A supported Zigbee USB coordinator (e.g. SONOFF Zigbee 3.0 USB Dongle Plus) plugged in
- ▸sudo or root access on the target Linux host
- ▸Internet access to download packages and clone the repository
Zigbee2MQTT bridges your Zigbee devices—sensors, bulbs, switches—to an MQTT broker, giving you local control without vendor clouds. It pairs naturally with Home Assistant, Node-RED, or any MQTT-capable automation platform. This guide covers the full stack: Mosquitto broker, coordinator adapter, the Zigbee2MQTT service, and the built-in web frontend.
Prerequisites and Hardware
You need a Zigbee USB coordinator—the most widely supported options are the SONOFF Zigbee 3.0 USB Dongle Plus (based on the CC2652P chip) and the SLZB-06 for Ethernet. Plug the coordinator in before starting and confirm the kernel sees it:
ls /dev/serial/by-id/
You should see a symlink like usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_.... Note the full path; you will use it in the Zigbee2MQTT config. If nothing appears, check dmesg | tail -20 for USB errors.
Step 1 – Install Mosquitto
Mosquitto is the de-facto MQTT broker for self-hosted setups. Install it from your distro's repositories.
Debian / Ubuntu
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
Fedora / RHEL 9 / Rocky 9
sudo dnf install -y mosquitto
Arch
sudo pacman -S mosquitto
Enable and start the service:
sudo systemctl enable --now mosquitto
By default Mosquitto 2.x ships with a config that rejects anonymous connections. Create a password file for Zigbee2MQTT:
sudo mosquitto_passwd -c /etc/mosquitto/passwd zigbee2mqtt
Enter a password when prompted. Then create or edit /etc/mosquitto/conf.d/local.conf:
sudo tee /etc/mosquitto/conf.d/local.conf <<'EOF'
listener 1883 127.0.0.1
allow_anonymous false
password_file /etc/mosquitto/passwd
EOF
Binding to 127.0.0.1 keeps the broker off the network. If Home Assistant runs on a different host, change this to 0.0.0.0 and protect port 1883 at the firewall. Restart Mosquitto after any config change:
sudo systemctl restart mosquitto
Step 2 – Install Node.js
Zigbee2MQTT requires Node.js 18 or later. Avoid the distro-packaged version on older LTS releases—it is often too old.
Debian / Ubuntu (NodeSource)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
Fedora / RHEL 9 / Rocky 9
sudo dnf module enable nodejs:20 -y
sudo dnf install -y nodejs npm
Arch
sudo pacman -S nodejs npm
Confirm the version:
node --version # should print v20.x.x or later
Step 3 – Install Zigbee2MQTT
The project recommends installing from source via Git to stay close to upstream releases.
sudo mkdir -p /opt/zigbee2mqtt
sudo chown $USER:$USER /opt/zigbee2mqtt
git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
npm ci
npm ci installs exact dependency versions from the lockfile. Expect it to take a few minutes the first time.
Step 4 – Configure Zigbee2MQTT
The configuration file lives at /opt/zigbee2mqtt/data/configuration.yaml. Copy the example and edit it:
cp /opt/zigbee2mqtt/data/configuration.yaml.example \
/opt/zigbee2mqtt/data/configuration.yaml
nano /opt/zigbee2mqtt/data/configuration.yaml
A minimal working configuration looks like this. Replace the serial port path and MQTT password with your own values:
cat /opt/zigbee2mqtt/data/configuration.yaml
homeassistant: false
mqtt:
base_topic: zigbee2mqtt
server: mqtt://localhost
user: zigbee2mqtt
password: YOUR_MQTT_PASSWORD
serial:
port: /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_...
frontend:
port: 8080
permit_join: false
Always use the /dev/serial/by-id/ path rather than /dev/ttyUSB0—the by-id symlink is stable across reboots; ttyUSBx numbers can shift if you add other USB devices.
Set homeassistant: true if you want automatic MQTT discovery in Home Assistant. Leave permit_join: false for now; you will flip it temporarily when pairing devices.
Step 5 – Create a systemd Service
Running Zigbee2MQTT as a systemd service gives you automatic restarts and journal logging. Create the unit file:
sudo tee /etc/systemd/system/zigbee2mqtt.service <<'EOF'
[Unit]
Description=Zigbee2MQTT
After=network.target mosquitto.service
Requires=mosquitto.service
[Service]
Type=notify
User=pi
WorkingDirectory=/opt/zigbee2mqtt
ExecStart=/usr/bin/node index.js
Restart=on-failure
RestartSec=10
WatchdogSec=60
[Install]
WantedBy=multi-user.target
EOF
Replace User=pi with your actual username. If you installed as root, you can use User=root, but running as an unprivileged user is strongly preferred. That user needs read/write access to the serial device:
sudo usermod -aG dialout $USER # Debian/Ubuntu/Fedora
# On Arch the group is 'uucp':
# sudo usermod -aG uucp $USER
Log out and back in for the group to take effect, then enable the service:
sudo systemctl daemon-reload
sudo systemctl enable --now zigbee2mqtt
Step 6 – Verify the Service
Check the service is running and watch the initial logs:
sudo systemctl status zigbee2mqtt
journalctl -u zigbee2mqtt -f
Healthy output includes lines like Zigbee2MQTT started! and MQTT publish: topic 'zigbee2mqtt/bridge/state'. If it fails immediately, look for serial port permission errors or MQTT connection refused—both are common first-run problems covered in the troubleshooting section below.
Open the web frontend in a browser:
xdg-open http://localhost:8080 # or navigate manually on a remote host
Step 7 – Pair Zigbee Devices
Pairing (joining) is controlled by the permit_join setting. Enable it temporarily from the frontend or by editing the config and restarting. The safer method is the frontend: open Settings → Permit join and toggle it on. It auto-disables after 254 seconds by default.
With joining permitted, put your device into pairing mode (usually by holding the reset button until an LED flashes). The frontend Devices tab shows newly joined devices in real time. Once paired, disable joining again immediately to prevent unauthorized devices from joining.
You can also toggle joining from the command line using mosquitto_pub:
mosquitto_pub -h localhost -u zigbee2mqtt -P YOUR_MQTT_PASSWORD \
-t zigbee2mqtt/bridge/request/permit_join \
-m '{"value": true, "time": 120}'
Troubleshooting
Serial port access denied
If the journal shows Error: Permission denied, cannot open /dev/ttyUSB0, the service user is not in the dialout (or uucp on Arch) group, or the group change hasn't taken effect. Verify with:
groups $USER
If the group is missing, add it and log out completely (a new SSH session is not enough if the original login session is still open). As a temporary workaround you can set the service User=root, but fix the group properly before production use.
MQTT connection refused
Confirm Mosquitto is listening:
ss -tlnp | grep 1883
Then test authentication separately:
mosquitto_sub -h localhost -u zigbee2mqtt -P YOUR_MQTT_PASSWORD -t 'zigbee2mqtt/#' -v
A credentials mismatch gives Connection Refused: not authorised. Regenerate the password file entry with mosquitto_passwd and ensure the same password is in configuration.yaml.
Coordinator not detected
Some CC2652-based dongles require a firmware update to work reliably on Linux 6.x kernels with the cp210x driver. Check the Z-Stack firmware repository for the latest coordinator firmware and flash it using the vendor's flashing tool before troubleshooting further.
Keeping Zigbee2MQTT Updated
Pull the latest code and reinstall dependencies:
cd /opt/zigbee2mqtt
git pull
npm ci
sudo systemctl restart zigbee2mqttFrequently asked questions
- Can I run Zigbee2MQTT without Home Assistant?
- Yes. Zigbee2MQTT is fully standalone. Set homeassistant: false in configuration.yaml and integrate with any MQTT-capable platform such as Node-RED, OpenHAB, or a custom application.
- My coordinator shows as /dev/ttyUSB0. Is that safe to use?
- It works but is fragile—the number can change after a reboot if other USB serial devices are present. Always use the stable symlink under /dev/serial/by-id/ in your configuration.
- How do I update Zigbee2MQTT?
- Run git pull in /opt/zigbee2mqtt, then npm ci, and restart the service with systemctl restart zigbee2mqtt. Your paired device database in the data/ folder is preserved.
- Does Zigbee2MQTT support Zigbee routers and mesh networking?
- Yes. Mains-powered Zigbee devices (bulbs, plugs) act as routers and extend the mesh automatically. Battery-powered end devices connect through the nearest router or directly to the coordinator.
- The coordinator needs a firmware update. How do I flash it?
- For CC2652-based dongles use the Texas Instruments Flash Programmer 2 on Windows, or the open-source cc2538-bsl Python tool on Linux. Download the latest coordinator firmware from the Koenkk/Z-Stack-firmware GitHub repository.
Related guides
Configure Prometheus Alertmanager
Configure Prometheus Alertmanager with routing trees, receivers, inhibition rules, grouping, Go templates, and PagerDuty/Slack on-call integrations.
Build an Intranet Server on Linux
Set up a complete small-office intranet on one Linux box: Nginx web server, dnsmasq local DNS, Samba file sharing, and a Wiki.js team wiki.
Build an nftables Firewall Script
Build a complete nftables firewall from scratch: tables, chains, sets, default-deny input policy, service allowlisting, and persistent systemd configuration.
Caddy as a Reverse Proxy
Set up Caddy as a reverse proxy with automatic HTTPS, load balancing, WebSocket passthrough, reusable snippets, and header control — no certbot required.