read_only=ON拦不住root,因其是“高权限豁免型”只读机制:root默认拥有SUPER和SYSTEM_VARIABLES_ADMIN权限,而该参数仅限制无此权限的普通用户,不构成强制访问控制。
MySQL 从库设了,root 还能写,不是配置失效,是权限设计如此。
为什么
拦不住 root?
因为
不是权限开关,而是“高权限豁免型”只读保护:只要用户拥有
或
权限,就能绕过该限制。MySQL 8.0.12+ 默认给
同时授予这两个权限,所以即使
返回
,
/
依然成功。
普通用户(如
)没显式授这俩权限,就会被拦住,报错:
是会话级检查,不校验账号角色,也不管你是不是复制线程——它只看当前连接用户的系统权限
云厂商 RDS 常默认关闭
,且禁止动态修改,得走控制台或白名单申请
才真能锁死 root
是 MySQL 5.7.20+ / 8.0+ 引入的强化版只读开关,启用后连
用户也无法执行 DML/DDL,且该变量不可动态关闭(除非先关它自己)。
必须在配置文件
的
段落中写死:
;仅靠
不可靠,重启即失效
MySQL 8.0.26+ 有联动机制:一旦
,
自动强制为
;但反过来不成立
注意陷阱:
只需
权限,不需要
——所以这个变量本身也要靠权限回收来守
真正封死写入的三步操作
单靠一个参数永远不够,必须组合加固:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
在
中同时设置:
和
,然后重启
或用
(需
权限)
回收 root 的越权能力:
,MySQL 8.0.12+ 还要追加:
验证是否生效:
输出里不能出现
或
;再试
,应报错
容易被忽略的“伪只读”行为
即使
生效,某些命令仍会产生 binlog 记录、改变 GTID 状态,造成主从逻辑不一致:
、
、
等语句会被写入 binlog(除非显式加
),产生新 GTID,导致
在主从上不一致
不影响
、
变量、
类命令,也不阻止 relay log 自动 purge(
必须单独确认)
如果从库意外开启了
,误写 + binlog 开启 = 错误数据可能被同步到下游,必须定期查
并确保为
最常被漏掉的一点:权限回收后没验证复制线程是否还能跑。SQL_THREAD 需要
权限,但不需要
;只要没误 revoke 这个权限,且
,从库就能持续同步——否则“只读”只是表象,实际已静默脱同步。
read_only=ONread_only=ONread_onlySUPERSYSTEM_VARIABLES_ADMINroot@localhostSHOW VARIABLES LIKE 'read_only'ONINSERTUPDATErepl_userThe MySQL server is running with the --read-only option so it cannot execute this statementread_onlyread_onlysuper_read_only=ONsuper_read_onlySUPERmy.cnf[mysqld]super_read_only=ONSET GLOBAL super_read_only = ONsuper_read_only=ONread_onlyONSET GLOBAL super_read_only = OFFSYSTEM_VARIABLES_ADMINSUPERmy.cnfread_only=ONsuper_read_only=ONmysqldSET PERSIST super_read_only = ONPERSIST_RO_VARIABLES_ADMINREVOKE SUPER ON *.* FROM 'root'@'localhost';REVOKE SYSTEM_VARIABLES_ADMIN ON *.* FROM 'root'@'localhost';SHOW GRANTS FOR 'root'@'localhost';SUPERSYSTEM_VARIABLES_ADMININSERTERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statementsuper_read_only=ONFLUSH TABLESANALYZE TABLEOPTIMIZE TABLENO_WRITE_TO_BINLOG@@global.gtid_executedsuper_read_onlySELECTSETSHOWrelay_log_purge=ONlog_binSHOW VARIABLES LIKE 'log_bin'OFFREPLICATION SLAVESUPERrelay_log_purge=ON