基于主从架构,先升级从库,切换后升级原主库,实现零停机原地升级
- 主库:192.168.195.141(MySQL 5.7.35 → 8.0.35)
- 从库:192.168.195.142(MySQL 5.7.35 → 8.0.35)
1. 环境信息
| 项目 | 主库 (Master) | 从库 (Slave) |
|---|---|---|
| IP | 192.168.195.141 | 192.168.195.142 |
| MySQL版本(升级前) | 5.7.35(二进制包,glibc2.12) | 5.7.35(二进制包,glibc2.12) |
| MySQL版本(升级后) | 8.0.35(二进制包,glibc2.17) | 8.0.35(二进制包,glibc2.17) |
| server-id | 1 | 2 |
| gtid_mode | ON | ON |
2. 升级方式说明
原地升级(In-Place Upgrade):直接在5.7的数据目录上启动8.0,MySQL自动完成数据字典升级。
主从架构升级策略:
- 先升级从库(142)→ 验证
- 主从切换(142提升为主库)
- 再升级原主库(141)→ 配置为新从库
- (可选)再次切换回原角色
优点:
- 无需导出导入数据,升级速度快
- 主从架构下可实现零停机升级
- 数据目录原地升级,无需额外磁盘空间
缺点:
- 升级过程不可逆,必须做好备份
- 数据字典升级过程中实例不可用
- 如果升级失败,回退较复杂
3. 前置条件:搭建 MySQL 5.7.35 GTID 主从
3.1 清理旧环境(两台均执行)
bash
systemctl stop mysqld
rm -rf /usr/local/mysql
rm -rf /data/mysql/3306/data/*
rm -f /etc/my.cnf
unlink /usr/local/mysql 2>/dev/null
3.2 安装 MySQL 5.7.35(两台均执行)
bash
groupadd mysql
useradd -g mysql mysql
cd /usr/local/
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz
tar xzf mysql-5.7.35-linux-glibc2.12-x86_64.tar.gz
ln -s mysql-5.7.35-linux-glibc2.12-x86_64 mysql
/usr/local/mysql/bin/mysql --version
# /usr/local/mysql/bin/mysql Ver 14.14 Distrib 5.7.35, for linux-glibc2.12 (x86_64) using EditLine wrapper
3.3 创建数据目录(两台均执行)
bash
mkdir -p /data/mysql/3306/data
chown mysql.mysql /data/mysql/3306/data/
3.4 编辑配置文件
主库 /etc/my.cnf(141)
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
log-bin = mysql-bin
server-id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
从库 /etc/my.cnf(142)
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
server-id = 2
gtid_mode = ON
enforce_gtid_consistency = ON
3.5 初始化实例(两台均执行)
bash
/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --initialize --user=mysql
获取临时密码:
bash
grep "temporary password" /data/mysql/3306/data/mysqld.err
# 141: A temporary password is generated for root@localhost: aij+#uemP2pJ
# 142: A temporary password is generated for root@localhost: /5#QW7ciU&M8
3.6 配置 systemd 服务(两台均执行)
创建 /etc/systemd/system/mysqld.service:
ini
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
Type=forking
PIDFile=/data/mysql/3306/data/mysqld.pid
TimeoutSec=0
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf --pid-file=/data/mysql/3306/data/mysqld.pid --daemonize $MYSQLD_OPTS
EnvironmentFile=-/etc/sysconfig/mysql
LimitNOFILE = 65535
Restart=on-failure
RestartPreventExitStatus=1
PrivateTmp=false
创建 /etc/sysconfig/mysql:
ini
MYSQLD_OPTS=
3.7 启动实例并修改密码(两台均执行)
bash
systemctl daemon-reload
systemctl start mysqld
systemctl enable mysqld
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -p'临时密码' --connect-expired-password -e "alter user user() identified by 'Root@123456';"
3.8 搭建 GTID 主从复制
主库(141)创建复制用户:
sql
CREATE USER 'repl'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
从库(142)建立复制:
sql
CHANGE MASTER TO
MASTER_HOST='192.168.195.141',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1;
START SLAVE;
验证:
sql
-- 从库执行
show slave status\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Auto_Position: 1
-- Seconds_Behind_Master: 0
3.9 插入测试数据
sql
-- 主库(141)执行
CREATE DATABASE test_upgrade;
USE test_upgrade;
CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(20));
INSERT INTO t1 VALUES (1,'before_upgrade'),(2,'mysql57'),(3,'gtid_test');
SELECT * FROM t1;
-- +----+----------------+
-- | id | name |
-- +----+----------------+
-- | 1 | before_upgrade |
-- | 2 | mysql57 |
-- | 3 | gtid_test |
-- +----+----------------+
从库验证:
sql
SELECT * FROM test_upgrade.t1;
-- 数据一致,主从复制正常
4. 原地升级步骤
4.1 下载 MySQL 8.0.35(两台均执行)
bash
cd /usr/local/
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz
tar xJf mysql-8.0.35-linux-glibc2.17-x86_64.tar.xz
4.2 第一步:升级从库(142)
4.2.1 停止从库复制
sql
-- 在从库(142)执行
STOP SLAVE;
4.2.2 停止MySQL服务
bash
systemctl stop mysqld
4.2.3 修改配置文件
编辑 /etc/my.cnf,新增8.0必需参数:
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
server-id = 2
gtid_mode = ON
enforce_gtid_consistency = ON
default_authentication_plugin = mysql_native_password
配置变更说明:
- 新增
default_authentication_plugin = mysql_native_password:8.0默认使用caching_sha2_password,需保持与5.7兼容- 去掉
query_cache_type/query_cache_size(如果5.7配置中有):8.0已移除查询缓存功能- 本环境5.7最小化配置中没有query_cache相关参数,无需去掉
4.2.4 切换软链接到8.0
bash
unlink /usr/local/mysql
ln -s mysql-8.0.35-linux-glibc2.17-x86_64 /usr/local/mysql
# 验证
/usr/local/mysql/bin/mysql --version
# /usr/local/mysql/bin/mysql Ver 8.0.35 for Linux on x86_64 (MySQL Community Server - GPL)
4.2.5 启动8.0(自动升级数据字典)
bash
systemctl start mysqld
重要:启动8.0时,MySQL会自动检测5.7的数据目录并执行升级。这个过程在error日志中可以看到。如果表很大,升级可能较慢。
4.2.6 检查升级日志
bash
grep -i 'upgrade' /data/mysql/3306/data/mysqld.err | tail -5
输出:
2026-07-26T15:39:30.963451+08:00 1 [System] [MY-011012] [Server] Starting upgrade of data directory.
2026-07-26T15:39:31.581496+08:00 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80035' started.
2026-07-26T15:39:32.760127+08:00 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80035' completed.
关键信息 :
Server upgrade from '50700' to '80035' completed表示升级成功完成。
4.2.7 验证从库升级
sql
-- 版本确认
SELECT VERSION();
-- 8.0.35
-- 数据完整性
USE test_upgrade;
SELECT * FROM t1;
-- +----+----------------+
-- | id | name |
-- +----+----------------+
-- | 1 | before_upgrade |
-- | 2 | mysql57 |
-- | 3 | gtid_test |
-- +----+----------------+
-- .frm文件已消除(8.0使用数据字典)
SELECT COUNT(*) AS frm_count FROM information_schema.FILES WHERE FILE_NAME LIKE '%.frm%';
-- 0
-- MyISAM系统表已转为InnoDB
SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='mysql' AND ENGINE='MyISAM';
-- Empty set(无MyISAM系统表)
-- GTID状态
SHOW VARIABLES LIKE 'gtid_mode';
-- ON
-- 认证插件
SHOW VARIABLES LIKE 'default_authentication_plugin';
-- mysql_native_password
4.2.8 再次重启确认
bash
systemctl restart mysqld
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -p'Root@123456' -e "SELECT VERSION();"
# 8.0.35
4.3 第二步:主从切换
将从库(142)提升为主库,原主库(141)降为从库。
4.3.1 在142上停止复制并提升为主库
sql
-- 在142执行
STOP SLAVE;
RESET SLAVE ALL;
-- 确认142可以独立运行
SHOW MASTER STATUS;
-- +---------------+----------+--------------+------------------+-------------------------------------------+
-- | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
-- +---------------+----------+--------------+------------------+-------------------------------------------+
-- | binlog.000002 | 157 | | | 9eec700e-88c4-11f1-9843-000c29048d1f:1-6 |
-- +---------------+----------+--------------+------------------+-------------------------------------------+
4.3.2 在142上创建复制用户
sql
-- 在142执行
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
4.4 第三步:升级原主库(141)
4.4.1 停止MySQL服务
bash
systemctl stop mysqld
4.4.2 修改配置文件
编辑 /etc/my.cnf:
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
log-bin = mysql-bin
server-id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
default_authentication_plugin = mysql_native_password
4.4.3 切换软链接到8.0
bash
unlink /usr/local/mysql
ln -s mysql-8.0.35-linux-glibc2.17-x86_64 /usr/local/mysql
/usr/local/mysql/bin/mysql --version
# /usr/local/mysql/bin/mysql Ver 8.0.35 for Linux on x86_64 (MySQL Community Server - GPL)
4.4.4 启动8.0(自动升级数据字典)
bash
systemctl start mysqld
4.4.5 检查升级日志
bash
grep -i 'upgrade' /data/mysql/3306/data/mysqld.err | tail -5
输出:
2026-07-26T15:42:16.743686+08:00 1 [System] [MY-011012] [Server] Starting upgrade of data directory.
2026-07-26T15:42:17.350511+08:00 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80035' started.
2026-07-26T15:42:18.508952+08:00 5 [System] [MY-013381] [Server] Server upgrade from '50700' to '80035' completed.
4.4.6 验证141升级
sql
SELECT VERSION();
-- 8.0.35
USE test_upgrade;
SELECT * FROM t1;
-- +----+----------------+
-- | id | name |
-- +----+----------------+
-- | 1 | before_upgrade |
-- | 2 | mysql57 |
-- | 3 | gtid_test |
-- +----+----------------+
4.4.7 再次重启确认
bash
systemctl restart mysqld
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -p'Root@123456' -e "SELECT VERSION();"
# 8.0.35
4.5 第四步:恢复主从架构
将141配置为142的从库,恢复主从复制(主从角色已互换:142为主,141为从)。
sql
-- 在141执行
CHANGE MASTER TO
MASTER_HOST='192.168.195.142',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_AUTO_POSITION=1,
GET_MASTER_PUBLIC_KEY=1;
START SLAVE;
验证主从状态:
sql
-- 在141执行
show slave status\G
Slave_IO_State: Waiting for source to send event
Master_Host: 192.168.195.142
Master_Port: 3306
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Auto_Position: 1
4.6 数据同步验证
sql
-- 在新主库(142)写入数据
USE test_upgrade;
INSERT INTO t1 VALUES (4,'after_upgrade_80');
SELECT * FROM t1;
-- +----+------------------+
-- | id | name |
-- +----+------------------+
-- | 1 | before_upgrade |
-- | 2 | mysql57 |
-- | 3 | gtid_test |
-- | 4 | after_upgrade_80 |
-- +----+------------------+
sql
-- 在新从库(141)查询验证
SELECT * FROM test_upgrade.t1;
-- +----+------------------+
-- | id | name |
-- +----+------------------+
-- | 1 | before_upgrade |
-- | 2 | mysql57 |
-- | 3 | gtid_test |
-- | 4 | after_upgrade_80 |
-- +----+------------------+
数据一致,主从复制正常!
5. 升级后全面验证
5.1 两台节点版本确认
sql
-- 141
SELECT VERSION();
-- 8.0.35
-- 142
SELECT VERSION();
-- 8.0.35
5.2 GTID状态确认
sql
-- 141(从库)
SHOW VARIABLES LIKE 'gtid_executed';
-- 9eeb4935-88c4-11f1-ab8f-000c29a59955:1-3, 9eec700e-88c4-11f1-9843-000c29048d1f:1-6
-- 142(主库)
SHOW VARIABLES LIKE 'gtid_executed';
-- 9eeb4935-88c4-11f1-ab8f-000c29a59955:1-3, 9eec700e-88c4-11f1-9843-000c29048d1f:1-6
两台GTID一致。
5.3 数据字典升级确认
sql
-- .frm文件已消除
SELECT COUNT(*) AS frm_count FROM information_schema.FILES WHERE FILE_NAME LIKE '%.frm%';
-- 0
-- MyISAM系统表已全部转为InnoDB
SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='mysql' AND ENGINE='MyISAM';
-- Empty set
5.4 认证插件确认
sql
SHOW VARIABLES LIKE 'default_authentication_plugin';
-- mysql_native_password
SELECT user, host, plugin FROM mysql.user WHERE user='repl';
-- +------+------+-----------------------+
-- | user | host | plugin |
-- +------+------+-----------------------+
-- | repl | % | mysql_native_password |
-- +------+------+-----------------------+
6. 兼容性注意事项
6.1 认证插件
MySQL 8.0默认使用 caching_sha2_password,5.7使用 mysql_native_password。原地升级后需在my.cnf中添加:
ini
default_authentication_plugin = mysql_native_password
否则5.7客户端可能无法连接8.0实例。
6.2 query_cache 相关参数
MySQL 8.0移除了查询缓存功能,以下参数在8.0中不再支持:
query_cache_typequery_cache_sizequery_cache_limit
如果5.7的my.cnf中有这些参数,升级到8.0前必须去掉,否则8.0无法启动。
6.3 8.0新增关键字
MySQL 8.0新增了 RANK、DENSE_RANK、ROW_NUMBER、GROUPS 等关键字。如果5.7中使用了这些名称作为表名或列名,升级后需要用反引号引用:
sql
-- 5.7中可以
CREATE TABLE rank (id INT);
-- 8.0中需要反引号
CREATE TABLE `rank` (id INT);
SELECT * FROM `rank`;
6.4 .frm文件
MySQL 8.0使用数据字典(Data Dictionary)替代了5.7的.frm文件。原地升级后,.frm文件会被自动清理。
6.5 数据字典自动升级
MySQL 8.0启动时会自动检测5.7的数据目录并执行升级,包括:
- 将MyISAM系统表转为InnoDB
- 升级数据字典格式
- 移除.frm文件
升级过程在error日志中可见,无需手动执行mysql_upgrade(8.0中已废弃)。
6.6 支持的升级路径
- 仅支持从MySQL 5.7 GA版本直接升级到8.0
- 不支持跨大版本升级(如5.6→8.0)
- 建议升级前先升级到5.7的最新小版本(如5.7.35→5.7.44),再升级到8.0
7. 升级后最终配置文件
/etc/my.cnf(141,升级后,当前为从库)
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
log-bin = mysql-bin
server-id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
default_authentication_plugin = mysql_native_password
/etc/my.cnf(142,升级后,当前为主库)
ini
[client]
socket = /data/mysql/3306/data/mysql.sock
[mysqld]
basedir = /usr/local/mysql
datadir = /data/mysql/3306/data
user = mysql
port = 3306
socket = /data/mysql/3306/data/mysql.sock
log_error = /data/mysql/3306/data/mysqld.err
log_timestamps = system
server-id = 2
gtid_mode = ON
enforce_gtid_consistency = ON
default_authentication_plugin = mysql_native_password
软链接(两台均相同)
/usr/local/mysql -> mysql-8.0.35-linux-glibc2.17-x86_64
8. 连接信息
bash
# 141(当前从库)
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -p'Root@123456'
# 142(当前主库)
/usr/local/mysql/bin/mysql -uroot -S /data/mysql/3306/data/mysql.sock -p'Root@123456'
9. 回退方案
原地升级不可逆,回退需要从备份恢复:
- 停止8.0实例
- 恢复5.7的数据目录备份
- 切换软链接回5.7:
unlink /usr/local/mysql && ln -s mysql-5.7.35-linux-glibc2.12-x86_64 /usr/local/mysql - 恢复5.7的my.cnf(去掉
default_authentication_plugin) - 启动5.7实例
重要 :原地升级前必须做好数据备份!数据无价。
10. 升级流程总结
┌─────────────────────────────────────────────────────────┐
│ MySQL 5.7 → 8.0 主从架构原地升级流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. 搭建5.7 GTID主从(141主,142从) │
│ ↓ │
│ 2. 升级从库142:停5.7 → 改my.cnf → 切软链接 → 启8.0 │
│ ↓ │
│ 3. 验证142升级成功(版本、数据、error日志) │
│ ↓ │
│ 4. 主从切换:142提升为主库,141降为从库 │
│ ↓ │
│ 5. 升级原主库141:停5.7 → 改my.cnf → 切软链接 → 启8.0 │
│ ↓ │
│ 6. 验证141升级成功 │
│ ↓ │
│ 7. 141配置为142的从库,恢复主从架构 │
│ ↓ │
│ 8. 数据同步验证,升级完成 │
│ │
│ 结果:141(从) ← 8.0.35 GTID复制 → 142(主) │
│ 两台均已从5.7.35原地升级到8.0.35 │
└─────────────────────────────────────────────────────────┘