只读报表库必须同时设置 read_only = on 和 super_read_only = on 才真正生效,仅设 read_only 对高权限账号无效;需配置 relay_log_recovery = on、innodb_flush_log_at_trx_commit = 2、禁用 log_bin,并用业务账号实测 insert/create temporary table 报错验证;还需最小权限账号+网络隔离防数据污染。

只读报表库必须同时设 read_only 和 super_read_only
单设 read_only = ON 对报表库毫无意义——root、监控账号、DBA 账号默认带 SUPER 权限,删表、建临时表、执行 ANALYZE TABLE 全部照常。真正生效的组合是:read_only = ON 必须写在配置文件 [mysqld] 段下,super_read_only = ON 紧跟其后(顺序不能颠倒)。MySQL 8.0.22+ 可用 SET PERSIST super_read_only = ON 自动落盘到 mysqld-auto.cnf,适合容器环境。
从库刷新策略不是“开/关”问题,而是“何时刷、刷什么”
报表库常见误区是把 slave_parallel_workers 调高来加速同步,但实际瓶颈往往在单个大事务或 DDL 后的 relay log 回放。正确做法是:
- 确保
relay_log_recovery = ON(重启生效),避免 crash 后 relay log 不完整导致 SQL 线程卡死 - 关闭
innodb_flush_log_at_trx_commit = 1→ 改为2,降低刷盘压力(报表库不承担主库写入职责) - 禁用
log_bin(除非要做级联复制),否则 binlog 写入会额外消耗 I/O -
slave_preserve_commit_order = OFF(5.7+ 默认 OFF),多线程回放时无需严格保序,提升吞吐
验证只读是否真锁死,别信 SHOW VARIABLES
SHOW VARIABLES LIKE 'read_only' 返回 ON 只说明变量值对,不代表权限链路已切断。必须用真实业务账号(非 root)登录,执行以下语句测试:
INSERT INTO test_report VALUES (NOW()); CREATE TEMPORARY TABLE tmp SELECT * FROM information_schema.TABLES LIMIT 1; SET SESSION sort_buffer_size = 4194304;
前两条应报 ERROR 1290 (HY000);第三条成功才说明 session 级变量不受限——这反而是合理行为,不影响只读语义。
只读 ≠ 安全,报表库仍需最小权限账号 + 网络隔离
即使 super_read_only = ON 开启,以下操作仍可能污染数据:
-
FLUSH LOGS或RESET MASTER:破坏复制位点,报表库若意外升为主库将丢失同步状态 - 应用用高权限账号连库执行健康检查,顺手
INSERT INTO health_check插入探活记录 - 未回收
UPDATE权限的账号修改mysql.user表,间接提权
所以必须创建专用账号,只授 SELECT、REPLICATION CLIENT、PROCESS,且限制来源 IP;生产环境建议在防火墙层禁止除应用服务器外的所有连接。











