MySQL从库必须启用read_only和super_read_only以防止主从数据不一致;前者限制普通用户写入,后者禁止SUPER权限用户写入,且需配置文件与动态设置双生效,并定期验证。

MySQL从库默认允许写操作,但生产环境必须禁用——否则主从数据不一致几乎不可避免。
为什么从库能写入却不能写
MySQL本身不强制区分主从角色,read_only 是个开关式配置,不启用时从库和普通实例无异,INSERT/UPDATE/DELETE 全部能执行。问题在于:这些写入不会同步到主库,也不会被主库的 binlog 记录,更不会复制给其他从库——相当于在从库上“悄悄造了一套私有数据”。一旦发生主库宕机、切换为新主库,这些数据就变成孤儿,或者在后续同步中被覆盖、冲突报错。
常见错误现象:Duplicate entry 报错、Slave_SQL_Running: No、应用读到“幻影数据”(主库没这条,从库有)。
-
read_only=ON只阻止普通用户写入,super权限用户仍可绕过(比如root) - 真正安全的做法是搭配
super_read_only=ON(MySQL 5.7+),它连super用户也限制 - 该设置不影响 SQL 线程自身重放 relay log 的写入,所以复制逻辑不受影响
如何正确设置 read_only 和 super_read_only
不能只改配置文件然后重启,因为运行中可能已有连接正在写入;也不能只临时 SET,因为服务重启后失效。必须两者结合。
- 在 my.cnf 中添加:
[mysqld] read_only=ON super_read_only=ON
- 动态生效(无需重启):
SET PERSIST read_only = ON;和SET PERSIST super_read_only = ON;(MySQL 8.0+) - MySQL 5.7 需用
SET GLOBAL,但下次启动会丢失,务必同步改配置文件 - 设置后检查:
SELECT @@read_only, @@super_read_only;两个都应返回1
哪些场景下 read_only 会意外失效
不是设了就万事大吉。几个典型漏点:
- 应用连接用了
root或其他带SUPER权限的账号——read_only对它无效,super_read_only才管用 - 从库启用了
log_slave_updates=OFF,又手动在从库建表/写入,后续如果把它提升为主库,这些 DDL/DML 没进 binlog,下游从库会直接断复制 - 某些运维脚本或监控工具(如 pt-heartbeat)需要写入测试表,得单独授权
REPLICATION CLIENT+ 显式指定跳过read_only的账号,而不是用通用账号硬扛
从库写入需求真实存在,该怎么处理
确实有合理场景需要从库写,比如报表临时表、缓存表、审计日志。但必须隔离、可控、可追溯。
- 新建专用账号,只授予目标数据库/表的
INSERT权限,且明确禁止DROP/ALTER - 这类表命名加前缀(如
tmp_、rep_),并在监控中排除,避免被误当业务表 - 绝不允许在业务库(如
order_db)里建临时表——哪怕只是CREATE TEMPORARY TABLE,也可能干扰备份或 DDL 同步 - 如果必须做从库读写分离,优先考虑中间件(如 ProxySQL)或应用层路由,而不是依赖从库自身状态
最麻烦的从来不是设不设 read_only,而是设完之后没人定期验证它是否还生效,也没人清理残留的高权限写入账号。


















