应为主库配置仅写权限账号(如app_rw)、从库配置仅读权限账号(如app_ro),二者账号、密码、授权范围严格分离,且replication用户仅需replication slave权限,禁用super等高危权限。

主库只给写权限,从库只给读权限怎么配
MySQL 读写分离场景下,最基础的安全动作就是让应用连接不同实例时,天然只能执行对应操作。不是靠代码自觉,而是靠权限卡死。
常见错误是给同一个账号在主从上都开 SELECT、INSERT、UPDATE 全量权限,结果从库被误写入,binlog 错乱,复制中断。
- 主库上只授予写权限:
GRANT INSERT, UPDATE, DELETE, CREATE, DROP, ALTER ON *.* TO 'app_rw'@'10.20.%'; - 从库上只授予读权限:
GRANT SELECT, SHOW VIEW ON *.* TO 'app_ro'@'10.20.%'; - 两个账号密码必须不同,避免配置错连后越权;且
app_ro不要在主库创建,app_rw不要在从库创建 - 注意:MySQL 权限是按 host + user 组合判定的,所以
'app_rw'@'10.20.%'和'app_rw'@'192.168.%'是两个独立账号,别漏掉网段
replication 用户要不要开 SUPER 权限
不要。5.7+ 版本中,REPLICATION SLAVE 权限已足够让从库拉取 binlog,SUPER 是高危权限,能 kill 线程、修改全局变量、绕过 max_connections 限制等。
典型错误是沿用老教程,直接 GRANT ALL PRIVILEGES ON *.* TO 'repl'@'%' WITH GRANT OPTION;,这等于把主库 root 的一半钥匙交出去了。
- 正确做法:
CREATE USER 'repl'@'10.20.%' IDENTIFIED BY 'xxx'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.20.%'; - 如果用的是 MySQL 8.0+,记得用
caching_sha2_password插件(默认),客户端需支持,否则连不上 - 该账号只用于主从同步,不给应用代码使用,也不加到任何连接池配置里
应用层读写分离后,权限校验还生效吗
生效,但只在校验连接建立那一刻。MySQL 不会动态感知你这条 SQL 是发给主库还是从库——它只看你当前连接用的是哪个账号、连的是哪台实例。
容易踩的坑是以为“用了 ShardingSphere 或 MyCat 就自动隔离权限”,其实这些中间件只是路由,底层仍是普通连接。一旦路由出错(比如强制走从库执行 UPDATE),而从库账号又恰好有写权限,就全完了。
- 务必在每台数据库实例上单独管理账号权限,不依赖中间件兜底
- 测试阶段用
SELECT USER(), CURRENT_USER();确认应用实际连的是哪个账号 - 从库账号禁止授予
LOCK TABLES、PROCESS、RELOAD等运维类权限,这些和只读目标无关,反而增加攻击面
高并发下权限变更会不会锁表或影响性能
不会锁业务表,但会短暂阻塞新连接建立,且权限变更本身是同步操作,主从延迟会导致权限不一致。
比如你在主库改了 app_rw 的密码,从库没同步完之前,新连主库的请求用新密码,连从库的还用旧密码——如果应用连接池混用,就会出现部分连接失败。
- 权限变更(
GRANT/REVOKE/ALTER USER)会刷新mysql.user表,并触发权限重载,耗时微秒级,但期间新建连接可能拿到旧缓存 - 生产环境建议在低峰期批量操作,避免高频
FLUSH PRIVILEGES(其实 GRANT 后自动触发,不用手动) - 更稳妥的做法:新增账号(如
app_rw_v2),切流量后再删旧账号,规避中间态风险
权限这事,表面是 GRANT 一行命令,实际是主从拓扑、连接路由、账号生命周期三者咬合的结果。少一个环节对齐,高并发下暴露的就是放大后的权限越界。











