读用户仅授SELECT权限,写用户授SELECT/INSERT/UPDATE/DELETE,禁用系统库权限,REPLICATION SLAVE仅用于从库同步,权限变更需重连生效,跨库查询须显式授权。

只给读用户 SELECT 权限,别碰 INSERT/UPDATE/DELETE
读写分离的前提是「人不能越权」,MySQL 本身不自动区分读写流量,靠的是应用连接不同账号——读账号连从库,写账号连主库。所以权限必须从账号粒度切开。
常见错误是给读用户加了 USAGE 或漏掉 GRANT OPTION 导致后续无法授权,或者误授 SHOW VIEW、LOCK TABLES 等隐式写权限。
- 读用户只执行:
GRANT SELECT ON mydb.* TO 'reader'@'%'; FLUSH PRIVILEGES; - 写用户才需要:
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'writer'@'%'; - 禁止对系统库(
mysql、information_schema)授任何权限,哪怕只读 - 如果用视图,
SELECT权限不够——还需SHOW VIEW,但这是潜在风险点,慎开
REPLICATION SLAVE 权限不是给应用用户的,是给从库同步用的
有人看到从库要同步,就顺手给应用账号加 REPLICATION SLAVE,这是典型混淆角色。这个权限只用于从库 I/O 线程拉取 binlog,和应用读写完全无关,且一旦拥有,就能获取主库所有 binlog 内容,属于高危权限。
真正该检查的是:从库上是否已禁用应用账号登录(比如绑定 skip-networking 或防火墙限制),否则读用户可能直连从库后执行非预期操作。
- 主库上无需给
reader或writer授REPLICATION SLAVE - 从库上建议用独立账号(如
repl)专管复制,且仅允许来自主库 IP - 应用账号在从库上只保留
SELECT,且最好限定 host 为应用服务器段,而非'%'
权限变更后,FLUSH PRIVILEGES 不一定立刻生效
MySQL 8.0+ 默认启用缓存,权限变更后,已建立的连接仍沿用旧权限,直到重连。这不是 bug,是设计——为了性能不每次都查权限表。
线上直接改权限却没效果?八成是应用没重建连接,或用了连接池没配置 testOnBorrow 类机制校验。
- 改完权限后,新连接立即生效;老连接需断开重连
- 连接池场景下,观察
Threads_connected是否回落,确认旧连接是否释放 - 测试时用
mysql -u reader -p -e "SELECT USER(), CURRENT_USER();"验证实际生效账号 - 别依赖
FLUSH PRIVILEGES强刷——它只刷新内存权限缓存,不解决连接复用问题
跨库查询(JOIN 或 USE other_db)会绕过单库权限限制
权限是按库+表控制的,但 SELECT * FROM db1.t1 JOIN db2.t2 这种语句,只要对 db1.t1 有 SELECT,就可能触发对 db2.t2 的隐式访问——而如果没显式授予 db2 权限,会报错 ERROR 1142 (42000): SELECT command denied to user。
更隐蔽的是:某些 ORM 自动生成跨库 SQL,或视图定义引用了其他库表,导致权限看似合理,运行时报错。
- 读用户权限必须覆盖所有实际涉及的库,不能只授主业务库
- 用
SHOW GRANTS FOR 'reader'@'%'检查完整权限列表,别只看建库语句 - 从库上若有同名但结构不同的表(比如归档库),更要确认权限是否精确匹配
权限不是设完就完的事,每次加表、改库、切分逻辑都得重新核对账号权限边界。最常被忽略的,是连接复用导致的权限延迟生效,以及跨库引用带来的隐式权限缺口。


















