MySQL从库需设read_only=ON并写入配置文件,8.0.22+建议加super_read_only=ON;Redis从节点执行CONFIG SET slave-read-only yes并写入redis.conf;PostgreSQL物理从库默认只读,需确认pg_is_in_recovery()返回t。
MySQL 主从架构下如何给从库加只读锁
生产环境的从库被误写入,几乎都是因为 read_only=0 且没设权限隔离。只靠应用层约定“不往从库写”根本不可靠,必须从数据库层强制限制。
核心操作就一条:登录从库 MySQL 实例,执行 SET GLOBAL read_only = ON;。但这只是临时生效,重启即失效,所以必须同步改配置文件。
-
my.cnf或mysqld.cnf的[mysqld]段里加一行:read_only = ON - 如果用的是 MySQL 8.0.22+,建议再加
super_read_only = ON(它会阻止 SUPER 权限用户绕过read_only) - 注意:开启
read_only后,普通用户连INSERT/UPDATE/DELETE都会被拒绝,但SELECT、SHOW、SET仍可执行 - 常见坑:主库也误配了
read_only = ON→ 导致主库无法写入,业务直接挂掉;务必确认只在从库节点上配
Redis 哨兵模式中让从节点拒绝写命令
Redis 本身没有全局“只读开关”,但从节点默认就不接受写命令——前提是没被手动 slaveof no one 或哨兵错误故障转移。
真正容易出事的是:哨兵集群脑裂或配置异常后,某个从节点被错误提升为主节点,又没及时降级,就会变成可写状态。
- 检查当前节点角色:运行
INFO replication,看role:slave且master_host不为空 - 强制锁定:在从节点上执行
CONFIG SET slave-read-only yes(注意不是readonly,是slave-read-only) - 该设置重启失效,需写入
redis.conf:添加slave-read-only yes - 别信
CONFIG GET返回值——某些旧版本 Redis 在哨兵管理下会忽略该配置,必须结合INFO replication和实际写入测试验证
PostgreSQL 流复制中防止从库被写入
PostgreSQL 的物理复制从库默认就是只读的,但很多人不知道:只要从库处于 recovery 状态,任何写操作都会报错 ERROR: cannot execute INSERT in a read-only transaction。这其实是安全的,但隐患藏在“退出恢复模式”这个动作里。
- 绝对禁止手动执行
pg_wal_rewind或pg_ctl promote,除非你明确要把它变为主库 - 检查是否仍在只读状态:连上去运行
SELECT pg_is_in_recovery();—— 返回t才安全 - 如果返回
f,说明它已脱离复制、变成可写主库,需立刻查pg_controldata输出和日志里的promote记录 - 某些自动化脚本会静默调用
pg_ctl promote,建议在所有部署脚本里 grep 一遍,删掉或注释掉这类调用
Ansible 批量配置多服务器只读策略时的权限与顺序陷阱
用 Ansible 统一推 read_only 配置看似省事,但最容易翻车的地方不在语法,而在节点角色识别和执行顺序。
- 别用
group_names粗暴区分主从——实际环境中可能有多个从组、跨机房从库、临时灾备节点,必须基于事实变量,比如db_role: replica - 修改配置后,不能直接
systemctl restart mysql:重启期间服务中断,且新配置可能因语法错误导致启动失败;应先mysql --defaults-file=/etc/my.cnf -e "SELECT 1"校验配置有效性 - 对 Redis/PostgreSQL 这类热加载不支持只读开关的服务,必须 reload 而非 restart,否则会中断复制连接;例如 Redis 用
redis-cli CONFIG REWRITE+kill -SIGUSR2(仅限支持版本) - 最常被忽略的一点:Ansible 的
become_user如果设成mysql,会导致无法写入/etc/my.cnf(权限不足);应保持become: true,用 root 改配置,再用对应服务用户重启进程
多服务器环境里,“只读”不是配个参数就完事,而是得盯住角色状态、配置持久性、服务生命周期和自动化工具的行为边界。少一个环节验证,就可能让某个节点在无人知晓的情况下悄悄变成可写状态。










