mysql权限模型是基于账户+主机的二维控制,权限在连接时匹配user@host并查系统表,同一用户从不同ip可能权限不同;须严格限制host、分层授权、启用ssl、区分认证插件、慎用动态权限,并注意权限缓存需flush privileges生效。

MySQL 用户权限模型本质是「基于账户+主机的二维控制」
MySQL 不像 postgresql 那样支持角色继承或行级策略,它的权限判断发生在连接建立时:先匹配 user@host 组合,再检查该账户在 mysql.user、mysql.db、mysql.tables_priv 等系统表中被授予的具体权限。这意味着同一用户名从不同 IP 连入,可能拥有完全不同的权限集。
常见错误是创建 'app'@'%' 并授全库权限,导致任意网络位置都能以该身份操作数据库——实际应严格限制 host 值,比如用 'app'@'10.20.30.%' 或具体应用服务器 IP。
最小权限原则必须落实到具体对象层级
生产环境禁止使用 GRANT ALL PRIVILEGES ON *.*,哪怕只给一个应用用户。应按需分层授权:
-
GRANT select, INSERT, UPDATE ON app_db.users TO 'app_rw'@'10.20.30.5'—— 仅允许对特定表做 DML -
GRANT EXECUTE ON PROCEDURE app_db.calc_report TO 'report_user'@'192.168.1.100'—— 仅调用存储过程,不暴露底层表 -
GRANT USAGE ON *.* TO 'monitor'@'127.0.0.1'+GRANT SELECT ON performance_schema.*—— 监控账号只读且禁用密码登录(IDENTIFIED WITH mysql_native_password BY '')
注意:MySQL 8.0+ 中 USAGE 权限不再等价于“无权限”,而是表示可连接但无任何操作权,适合做占位或后续叠加授权。
密码策略与连接安全不能依赖权限系统兜底
权限隔离只管「能做什么」,不管「怎么连进来」。若未启用 TLS,明文传输的账号密码极易被嗅探;若密码强度弱,暴力破解风险陡增。
实操建议:
- 强制开启 SSL:在
my.cnf中配置require_secure_transport = ON - 限制认证插件:
ALTER USER 'app_rw'@'10.20.30.5' IDENTIFIED WITH caching_sha2_password REQUIRE X509 - 定期轮换密码并禁用历史密码重用:
ALTER USER 'app_rw'@'10.20.30.5' PASSWORD EXPIRE INTERVAL 90 DAY
特别注意:MySQL 5.7 默认用 mysql_native_password,而 8.0 默认改用 caching_sha2_password,客户端不升级可能导致连接失败,不是权限问题,是认证协议不匹配。
动态权限(MySQL 8.0+)让细粒度控制成为可能,但别滥用
传统静态权限(如 SELECT)作用于整个语句,而动态权限如 BACKUP_ADMIN、CLONE_ADMIN、CONNECTION_ADMIN 是全局开关,用于管理类操作。它们不替代对象级权限,而是补充。
典型误用:
- 给应用用户加
SUPER权限来解决「无法 kill 自己会话」问题 → 应改用CONNECTION_ADMIN+KILL权限组合 - 为支持备份脚本而开放
FILE权限 → 实际应使用BACKUP_ADMIN配合mysqldump --single-transaction
动态权限需显式授予,不会随 GRANT ALL 自动获得,且不能跨账户传递——这点比角色模型更可控,但也意味着每次新增管理需求都要人工确认授权范围。
最易被忽略的是权限缓存:修改 mysql.user 后,已连接会话不会立即失效,需执行 FLUSH PRIVILEGES 或等待 wait_timeout 超时断开重连。线上变更务必验证生效时机。