主从切换升级前必须确认4个状态:1. Slave_IO_Running和Slave_SQL_Running均为Yes;2. Seconds_Behind_Master稳定为0达60秒;3. MASTER_POS_WAIT或WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS返回0;4. FLUSH TABLES WITH READ LOCK后主从同表COUNT(*)一致。

主从切换升级前必须确认的 4 个状态点
停写旧主、升主新库不是“看到 Seconds_Behind_Master = 0 就切”,这个值在并行复制下极易假归零。真正可靠的是四个硬性检查项,缺一不可:
-
Slave_IO_Running和Slave_SQL_Running都为Yes(只看运行态,不看延迟) -
Seconds_Behind_Master稳定为0至少 60 秒(避免瞬时追平后 relay log 又堆积) - 在从库执行
SELECT MASTER_POS_WAIT('file_name', position, 10)或 GTID 模式下SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS('xxx', 10),返回值必须是0 - 主库执行
FLUSH TABLES WITH READ LOCK后,立刻在从库查同表COUNT(*),结果必须完全一致(锁只持几秒,但这是最终一致性快照)
从库升级时不能直接启动新版本 mysqld
跨大版本(如 5.7 → 8.0)或 even minor 升级(如 8.0.33 → 8.0.39),老数据目录不能被新 mysqld 直接启动——系统表结构已变,可能卡死在初始化阶段或静默损坏 mysql 库。
正确做法是分步控制复制线程和启动流程:
- 先执行
STOP SLAVE SQL_THREAD(保留IO_THREAD继续拉 binlog,防丢写入) - 关闭旧 mysqld,替换
basedir(bin、lib等),但datadir不动 - 检查配置:移除废弃参数(如
innodb_locks_unsafe_for_binlog),确认default_authentication_plugin客户端兼容(caching_sha2_password不支持就临时设为mysql_native_password) - 启动新版本后,立即
START SLAVE,再等Seconds_Behind_Master = 0且Slave_SQL_Running_State显示Slave has read all relay log
切主时最容易被绕过的 write 权限漏洞
执行 SET GLOBAL read_only = ON 后,你以为写入停了?错。SUPER 权限用户、触发器、存储过程里的 INSERT/UPDATE 仍可执行,而且不会报错——这些变更不会同步到从库,切主后立刻引发主键冲突、唯一索引失败或数据静默丢失。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
必须叠加防护:
- 切主前确认
super_read_only = ON(SHOW VARIABLES LIKE '%read_only%'查两项都生效) - 禁用所有 SUPER 用户或临时回收权限:
REVOKE SUPER ON *.* FROM 'admin'@'%' - 检查是否有未审计的触发器或事件调度器:
SELECT * FROM information_schema.TRIGGERS、SELECT * FROM mysql.event - 用业务账号连上去试写一条:
INSERT INTO test_table VALUES (NOW()),必须报ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
DNS 缓存和连接池导致的“假切换”
你改完了 VIP、刷完了 DNS、应用日志显示“已连新主”,但部分请求还在打旧主——这不是网络问题,是客户端缓存没清。
Java 应用尤其典型:
- HikariCP 连接池默认复用空闲连接,
setReadOnly(true)或evict()必须显式调用,不能靠超时淘汰 - Tomcat JNDI 数据源需重启或手动刷新
DataSource实例 - DNS TTL 若设为 300 秒,切换前必须提前
dig +short your-db.example.com确认解析已更新,否则本地/etc/hosts或中间 DNS 缓存会持续转发 5 分钟 - 若用了 ProxySQL,必须执行
SERIALIZE TO CONFIG(非SAVE TO CONFIG)并RELOAD PROXYSQL,否则路由规则不生效
最隐蔽的坑是:升级后 SELECT USER() 返回空或报错,这往往意味着 mysql_upgrade 没跑,或者 mysqld --upgrade 被跳过——系统表结构不匹配会导致权限校验崩溃,而这个问题在连接池复用旧连接时根本不会暴露,直到第一个新连接建立才炸。

















