Skip to main content

Command Palette

Search for a command to run...

Zero-Downtime Zabbix Migration: How I Moved from 6.4 to 7.0 Without Losing a Single Metric

When your monitoring environment grows, it starts screaming for an upgrade. More hosts, items, and triggers appear, the UI slows down, caches run out

Updated
4 min read
Zero-Downtime Zabbix Migration: How I Moved from 6.4 to 7.0 Without Losing a Single Metric

Overall Architecture: Why It Works

Zabbix Server on Server 2 is the brain of the operation: it caches configuration, processes triggers, and writes data into the database.
Frontend (running on Apache) provides dashboards, graphs, and configuration UI.
Database (MySQL/MariaDB) stores history, trends, and metadata.
Zabbix Proxies sit across sites — while the main server is cut over, they buffer data and later push it in bulk. That’s what makes the whole migration safe.


Before Starting: Backup and Freeze

I scheduled a short data freeze to ensure nothing was written during the dump. Then I took a clean backup of the Zabbix database and temporarily stopped the old server — so the dump wouldn’t get interrupted.
Proxies kept collecting data in their buffers, waiting to sync afterward.

Be sure to take snapshots of your machines and make sure you have backups before you start.

# consistent backup + clean handoff
mysqldump --single-transaction -u root -p zabbix > /tmp/zabbix_$(date +%F).sql
sudo systemctl stop zabbix-server

# also save configs for safety
# /etc/zabbix/* and /etc/zabbix/web/zabbix.conf.php (if local)

Building Server 2: Apache + PHP 8 + Database + Zabbix 7.0

I built the new environment in order: web stack → database → Zabbix.
If you get the classic ERROR 2002 (socket) while connecting to MySQL, it simply means the MySQL service isn’t installed or running.

# web stack
sudo apt update
sudo apt install -y apache2 php php-{mysql,mbstring,xml,bcmath,gd,curl}

# DB server
sudo apt install -y mysql-server
sudo systemctl enable --now mysql
sudo mysql   # enter MySQL shell (Ubuntu uses socket auth)

Create a dedicated Zabbix database with utf8mb4_bin to avoid Unicode comparison issues, and a user with proper privileges:

CREATE DATABASE zabbix CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'zabbix'@'localhost' IDENTIFIED BY 'StrongPass!';
GRANT ALL PRIVILEGES ON zabbix.* TO 'zabbix'@'localhost';
FLUSH PRIVILEGES;

Then add the official Zabbix 7.0 repository and install the packages:

wget https://repo.zabbix.com/zabbix/7.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo apt update
sudo apt install zabbix-server-mysql zabbix-frontend-php zabbix-apache-conf zabbix-sql-scripts zabbix-agent2
sudo apt install zabbix-agent2-plugin-mongodb zabbix-agent2-plugin-mssql zabbix-agent2-plugin-postgresql

Restoring Data and Connecting Services

Once the database was ready, I restored the dump and pointed both the server and frontend to it. If you skip this carefully, you’ll face DB/frontend mismatches later.

# bring back your history and config
mysql -u root -p zabbix < /tmp/zabbix_YYYY-MM-DD.sql

# configure DB parameters for the Zabbix server
sudo nano /etc/zabbix/zabbix_server.conf
# DBName=zabbix
# DBUser=zabbix
# DBPassword=StrongPass!
# DBHost=127.0.0.1

# enable frontend configuration for Apache
sudo a2enconf zabbix-frontend-php
sudo systemctl reload apache2

Don't forget to change the IP on the second server back to the previous Zabbix IP or apply your changes to DNS!

When you start Zabbix 7.0, it automatically upgrades the schema. I monitored the logs during this step.
If the UI complains like “DB version 6050035, required 7000000,” it means the new server hasn’t fully upgraded the DB yet — or your binlog trust settings are blocking it.

# start services and watch logs
sudo systemctl enable --now zabbix-server zabbix-agent apache2
sudo tail -f /var/log/zabbix/zabbix_server.log

# if mismatch: verify versions and DB targets, then temporarily trust function creators
zabbix_server -V
grep -E 'DB(Name|User|Host)' /etc/zabbix/zabbix_server.conf
grep -E 'DB(Name|User|Host)' /etc/zabbix/web/zabbix.conf.php
sudo mysql -e "SET GLOBAL log_bin_trust_function_creators=1;"
sudo systemctl restart zabbix-server
# revert after upgrade
sudo mysql -e "SET GLOBAL log_bin_trust_function_creators=0;"

Breathing Room for the Caches

For a busy infrastructure, CacheSize=32M is a joke. I bumped it to 1 GB (2–4 GB for very large environments). Then I verified /dev/shm was big enough for shared memory — ideally double the cache size. Using the internal item zabbix[rcache,buffer,pused], I kept cache utilization between 40–60%. Anything above 70% meant it was time to increase it again.

# give config cache real headroom
sudo sed -i 's/^#\?CacheSize=.*/CacheSize=1024M/' /etc/zabbix/zabbix_server.conf
sudo systemctl restart zabbix-server
sudo tail -f /var/log/zabbix/zabbix_server.log

# ensure shared memory is large enough (≥ 2× CacheSize)
df -h /dev/shm

Post-Cutover Validation

Once the cutover was done, I confirmed all Proxies were Connected, Latest Data was flowing, and media/actions worked correctly.
If the UI complained about missing PHP extensions or timezone issues, fixing them and reloading Apache solved it quickly.

These small checks make the following day calm and predictable.

Rollback tip: If you ever need to revert, just stop services on Server 2, restore the pre-migration backup, point DNS back to Server 1, and review logs before retrying.

Final Thoughts

This migration reinforced one core lesson: a Zabbix upgrade isn’t hard if your proxies and database hygiene are solid. Plan your freeze, verify each step, and keep an eye on logs — that’s 90% of the job.