MySQL从库需设read_only=1防误写,但SUPER用户仍可写入,故5.7+应叠加super_read_only=1;同时须配合账号级SELECT权限控制,并实测验证生效。

MySQL 从库设置 read_only=1 是最基础的只读保障
主从架构中,从库默认不禁止写入,人为或应用误连从库执行 UPDATE/DELETE/INSERT 会导致数据漂移,破坏复制一致性。必须显式启用 read_only 系统变量。
在从库的 my.cnf 中添加:
[mysqld] read_only = 1
重启 MySQL 或动态生效(需 SUPER 权限):
SET GLOBAL read_only = ON;
注意:read_only 不影响 SUPER 用户,所以务必同时限制高权限账号访问从库;它也不阻止 SQL 线程自身写入(即复制操作仍可进行),这是设计预期。
禁止 SUPER 用户在从库写入:用 super_read_only 补漏
read_only 对 SUPER 用户无效,而运维脚本、备份工具或 DBA 临时连接常带 SUPER 权限,容易绕过只读限制。MySQL 5.7+ 提供 super_read_only 变量,开启后连 SUPER 用户也无法写入(除 SQL 线程外)。
启用方式(动态优先,避免重启):
SET GLOBAL super_read_only = ON;
该变量依赖 read_only=ON,若后者为 OFF,则 super_read_only 设为 ON 会自动把 read_only 拉起。生产环境建议两者都设,并写入配置文件:
[mysqld] read_only = 1 super_read_only = 1
检查是否生效:
SELECT @@read_only, @@super_read_only;
返回均为 1 才算真正锁死写入通道。
用账号权限控制替代“全库只读”,更精准
仅靠 read_only 是实例级防护,无法区分业务角色。应配合账号粒度授权,例如让报表用户只能查特定库表:
- 创建专用只读账号:
CREATE USER 'reporter'@'%' IDENTIFIED BY 'pwd123';
- 仅授予
SELECT权限(不含INSERT/UPDATE/DELETE/CREATE等):GRANT SELECT ON `sales_db`.* TO 'reporter'@'%';
- 刷新权限:
FLUSH PRIVILEGES;
关键点:read_only 和账号权限是正交机制——前者防误操作,后者控访问边界。即使某账号有 SUPER 权限,只要没显式授权写权限,日常查询仍受 GRANT 约束;而 super_read_only=ON 则进一步堵住 SUPER 的写入口。
验证只读是否真实生效:别只信配置文件
配置写完不等于生效,常见疏漏包括:变量未全局设置、配置文件加载错误、MySQL 版本不支持 super_read_only(如 5.6)、或被启动脚本覆盖。
上线前务必实测:
- 用普通账号尝试写:
INSERT INTO test.t1 VALUES (1); → 应报错 ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
- 用 root/SUPER 账号尝试写:
UPDATE test.t1 SET id=2 WHERE id=1; → 若
super_read_only=OFF,此操作会成功,立即破坏一致性 - 检查复制线程是否仍在运行:
SHOW SLAVE STATUS\G
中Slave_SQL_Running: Yes且Seconds_Behind_Master非持续增长,说明只读未干扰复制本身
最容易被忽略的是:某些中间件(如 ProxySQL、ShardingSphere)或 ORM 连接池会复用连接并缓存权限状态,修改权限后需重启连接池或触发连接重建,否则旧连接仍可能持有旧权限上下文。










