mysql的read_only=on默认不限制root等高权限用户写入,因其是权限感知型开关;真正全局只读需组合super_read_only=on、回收super权限,并在必要时使用flush tables with read lock加引擎层全局锁。

只读模式不是“设了就锁死”,read_only = ON 默认只拦普通用户,root 和带 SUPER 权限的账号照常写入——这不是配置失败,是 MySQL 的设计逻辑。
为什么 SET GLOBAL read_only = ON 后 root 还能 INSERT?
MySQL 的 read_only 是权限感知型开关,不是强制访问控制层。它只在 SQL 层做检查:只要当前连接用户拥有 SUPER 或 SYSTEM_VARIABLES_ADMIN 权限(MySQL 8.0.12+ 默认给 root 装齐了),写操作就直接放行。
- 常见错误现象:
SELECT @@global.read_only;返回1,但用mysql -u root -p执行INSERT仍成功 - 验证方式不能只看变量值,必须用业务账号实测:
mysql -u app_user -p -e "INSERT INTO t VALUES (1);" - 该行为在主从架构中合理——从库设
read_only = ON就是为了防误连写入,但允许 DBA 用 root 紧急修复复制中断
如何让 read_only 真正生效(含 root)?
单靠 read_only 永远不够。要封死所有写入口,必须组合两件事:启用 super_read_only + 收回高权限。
-
super_read_only依赖read_only = ON,顺序不能错:SET GLOBAL read_only = ON;→SET GLOBAL super_read_only = ON; - MySQL 5.7.8+ 才支持
super_read_only;5.6 或更早版本执行会报错:Unknown system variable 'super_read_only' - 永久生效必须写进配置文件:
/etc/my.cnf的[mysqld]段下加两行:read_only = ON和super_read_only = ON,然后重启mysqld - 回收权限才是兜底:
REVOKE SUPER, SYSTEM_VARIABLES_ADMIN ON *.* FROM 'root'@'localhost';,否则super_read_only可被有权限者动态关闭
配置写进 my.cnf 却不生效?排查这三处
配置文件写对位置、值格式、加载路径,缺一不可。
- 必须放在
[mysqld]段下,写在[client]或[mysql]里会被完全忽略,甚至导致启动失败 - 值只认
ON/OFF(大小写不敏感),别写成1、true或yes,MySQL 会静默当无效 - 确认没被多个配置文件覆盖:
mysqld --help --verbose | grep "Default options"查实际加载路径;云数据库(如阿里云 RDS)可能禁用该参数,需走控制台开关 - 改完必须重启:
systemctl restart mysqld,systemctl reload mysqld不触发重载read_only
迁移或备份时,仅 read_only = ON 不够安全
它拦不住 CREATE FUNCTION、ANALYZE TABLE、OPTIMIZE TABLE 这类元数据或统计信息变更,也不阻塞事务提交。真正需要“绝对只读”的场景(比如物理备份、主从切换窗口),必须用:
FLUSH TABLES WITH READ LOCK;
这条命令加的是存储引擎层全局读锁,所有用户(含 root)都无法执行任何写操作,包括 DML、DDL、TRUNCATE、甚至 SET 变量。释放锁用:UNLOCK TABLES;。注意:它会阻塞所有写线程,务必控制执行时长。
真正难的不是设参数,而是想清楚你要防谁、防什么操作、持续多久——read_only 是轻量护栏,super_read_only + 权限回收是加固门禁,FLUSH TABLES WITH READ LOCK 才是断电锁门。











