mysql 8.0最小权限实践需严格遵循五步闭环:①create user必须显式指定host(如10.20.30.0/24)和认证插件(caching_sha2_password或mysql_native_password);②grant必须按业务表粒度精确授权,禁用with grant option;③强制使用角色封装权限并set default role;④定期审计空密码、永不过期、通配符主机等高危配置;⑤验证须用show grants ... using role,且注意长连接需手动set role。

MySQL 8.0 权限最小化不是“设个密码+删个test库”就完事,而是从账号创建、授权粒度、主机限制、角色封装到权限审计的完整闭环。漏掉任意一环,都可能让最小化形同虚设。
CREATE USER 必须带明确 host 和认证插件
MySQL 8.0 默认使用 caching_sha2_password 插件,但很多旧客户端不兼容;如果直接用 CREATE USER 'app'@'%' 不指定插件,可能被自动降级为 mysql_native_password,导致后续连接失败或密码策略失效。
- 显式指定插件和密码强度:
CREATE USER 'app_rw'@'10.20.30.%' IDENTIFIED WITH caching_sha2_password BY 'P@ssw0rd_2024!'; - host 不能写
'%'—— 它允许任意公网 IP 连接,必须缩窄到具体子网或 CIDR(如'10.20.30.0/24') - 禁止创建空用户名:
SELECT user, host FROM mysql.user WHERE user = '';,存在则立即DROP USER ''@'localhost';
GRANT 必须精确到表,且禁用 GRANT OPTION
常见错误是 GRANT SELECT ON mydb.* TO 'reporter'@'%':它把所有表(含 config、audit_log)全放开,且 '%' 主机段暴露在公网。
- 先确认真实访问表:开
general_log跑一轮业务请求,再查SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(argument, ' ', 3), ' ', -1) FROM mysql.general_log WHERE argument LIKE 'SELECT %' OR argument LIKE 'UPDATE %'; - 按需授权,例如只读订单与用户信息:
GRANT SELECT ON mydb.orders TO 'reporter'@'10.20.30.0/24';GRANT SELECT ON mydb.users TO 'reporter'@'10.20.30.0/24'; - 绝对禁用:
GRANT ... WITH GRANT OPTION—— 它等于把权限分发权交给了应用账号
MySQL 8.0+ 必须用角色(Role)封装权限组合
直接给用户授予权限会导致权限散落、难以批量回收。角色不是可选项,是生产环境的必需基础设施。
- 建角色并赋权(注意粒度):
CREATE ROLE 'app_reader', 'app_writer';GRANT SELECT ON mydb.orders TO 'app_reader';GRANT INSERT, UPDATE ON mydb.orders TO 'app_writer'; - 绑定用户并激活默认角色:
GRANT 'app_reader' TO 'webapp'@'10.20.30.0/24';SET DEFAULT ROLE 'app_reader' TO 'webapp'@'10.20.30.0/24'; - 验证时别用
SHOW GRANTS FOR 'webapp'@'...'—— 它不显示角色权限;得用SHOW GRANTS FOR 'webapp'@'...' USING 'app_reader';
权限校验与清理必须常态化,不能只做一次
上线初期跑一遍 mysql_secure_installation 只是起点。真正的风险往往来自后续迭代中新增的账号、临时调试账号未回收、或备份脚本误用高权限账号。
- 定期检查高危配置:
SELECT user, host FROM mysql.user WHERE authentication_string = '' OR password_lifetime = 0;(空密码或永不过期) - 查是否有越权账号:
SELECT * FROM mysql.role_edges WHERE TO_HOST = '%';(角色被授予给通配符主机) - 备份账号权限必须独立校验:
mysqldump只需SELECT+LOCK TABLES+REPLICATION CLIENT,绝不能有DROP或ALTER
最容易被忽略的是:角色权限不会自动继承到已存在的会话中,SET DEFAULT ROLE 只对新连接生效;老连接仍需手动执行 SET ROLE,否则权限不生效——这点在长连接池场景下极易踩坑。











