必须同时开启read_only和super_read_only并写入配置文件,再配合权限收束与主从切换自动解锁机制,才能真正防止从库越权写入。

要真正防住从库被人为越权写入,光设 read_only=ON 是远远不够的——它对 root、DBA 账号这类拥有 SUPER 权限的用户完全无效。必须把 read_only 和 super_read_only 当作一对“双锁”来配置,再配合权限收束和流程卡点,才能堵死所有常见误写路径。
必须同时开启两个变量,且顺序不能错
read_only 只拦普通用户;super_read_only 才拦 root 和所有高权限账号。二者是“与”关系,缺一不可:
- 先执行
SET GLOBAL read_only = ON,再执行SET GLOBAL super_read_only = ON;反过来会报错ERROR 1290 - 必须写进配置文件(如
/etc/my.cnf的[mysqld]段),否则重启后失效:
[mysqld]
read_only = ON
super_read_only = ON - 检查是否生效:运行
SELECT @@read_only, @@super_read_only;,两个结果都应为1
权限管控不能只靠开关,要砍掉源头
即使开了 super_read_only,如果应用或脚本仍用带 SUPER 权限的账号连从库,就可能触发非 SQL 写行为(比如 FLUSH LOGS、调用含写逻辑的函数)。所以必须做减法:
- 从库上禁止授予
SUPER、REPLICATION CLIENT(除非真需查复制状态)、SHUTDOWN、CREATE USER等高危权限 - 应用账号只给
SELECT和EXECUTE(存过);DBA 登录从库必须用专用只读账号,例如:
CREATE USER 'ro_dba'@'%' IDENTIFIED BY 'xxx';
GRANT SELECT ON *.* TO 'ro_dba'@'%'; - 系统库也要防护:
REVOKE DROP, CREATE, ALTER ON mysql.* FROM 'appuser'@'%';
主从切换时必须自动解锁,不能靠人盯
从库升主后,若 read_only 和 super_read_only 还开着,SQL 线程会直接卡死(Slave_SQL_Running: No),业务写入中断。必须由高可用组件自动处理:
- MHA:在
master_ip_failover脚本末尾加:
mysql -h新主IP -e "SET GLOBAL read_only=0; SET GLOBAL super_read_only=0;" - Orchestrator:通过
PostMasterFailoverProcesses调用脚本,先判断SELECT @@read_only是否为 1,再执行关闭 - 切完立刻验证:
SHOW SLAVE STATUS\G中Slave_IO_Running和Slave_SQL_Running都应为Yes
上线前务必真实账号实测,别信“设了就行”
配置改完不测试,等于没配。拿一个带 SUPER 权限的真实账号(比如 root)连从库,手动试以下操作:
-
INSERT INTO test.t1 VALUES (1);→ 应报ERROR 1290 -
DROP TABLE test.t1;→ 同样报错 -
FLUSH LOGS;、RESET SLAVE;、SET GLOBAL max_connections = 1000;→ 全部应被拒绝 - 用只读账号登录后尝试写操作 → 应报
ERROR 1290或权限不足











