mysql中用户权限的最小化原则与实践

1次阅读

直接GRANT ALL ON .极危险,因赋予DROP database、SHUTDOWN等高危权限,应用账号亦可删库或重启实例;应遵循最小权限原则,按实际sql需求精确授权,禁用GRANT OPTION,优先细化到表或列,并利用mysql 8.0角色与动态权限机制实现安全管控。

mysql中用户权限的最小化原则与实践

为什么直接 GRANT ALL ON *.* 很危险

因为这会让用户拥有 DROP DATABASESHUTDOWNRELOAD 等高危权限,哪怕只是应用连接账号,也能意外删库或重启实例。MySQL 8.0 默认启用 sql_mode=STRICT_TRANS_tableS,但权限宽松本身不触发任何警告,风险完全靠人控制。

最小化不是“能连上就行”,而是“只给当前业务 SQL 真正需要的权限”。比如一个只查订单列表的接口,连 INSERT 都不该有。

  • 应用账号绝不分配 GRANT OPTION —— 否则可能自行提权
  • 避免使用 ON *.*ON database.*,优先细化到表甚至列(如 select(order_id, status) ON db.orders
  • MySQL 8.0+ 支持角色(CREATE ROLE),可用角色封装权限组合,再授给用户,便于批量调整

如何用 SHOW GRANTS 定位冗余权限

SHOW GRANTS for 'app_user'@'10.20.%' 返回的是当前生效权限集合,但注意:它不区分权限来源(是直授还是通过角色继承),也不显示已撤销但未刷新的缓存。真正要确认最小集,得结合实际运行日志反推。

推荐做法是开启 general_log(仅临时),让应用跑完典型链路(登录 → 查询 → 提交),再 grep 出所有 SELECT/UPDATE 语句涉及的库、表、字段:

SELECT DISTINCT   SUBSTRING_INDEX(SUBSTRING_INDEX(argument, ' ', 3), ' ', -1) AS table_name,   SUBSTRING_INDEX(argument, ' ', 2) AS stmt_type FROM mysql.general_log WHERE argument LIKE 'SELECT %' OR argument LIKE 'UPDATE %'   AND argument NOT LIKE '%information_schema%'   AND event_time > NOW() - INTERVAL 5 MINUTE;

结果出来后,再用 GRANT SELECT(col1,col2) ON db.table TO ... 精确授权,比凭经验猜更可靠。

MySQL 8.0 的动态权限与旧版兼容陷阱

MySQL 8.0 把部分管理权限(如 BACKUP_ADMINCLONE_ADMIN)从全局权限中拆出,变成可独立授予的「动态权限」。它们不会出现在 SHOW GRANTS 的传统输出里,必须用 SHOW GRANTS FOR 'u'@'h' using role_name 或查 mysql.role_edges 才能看到。

容易踩的坑:

  • 用 Percona Toolkit 或某些 ORM 连接池初始化时,默认尝试 SET session sql_log_bin = 0,需要 BINLOG_ADMIN 权限 —— 但该权限在 5.7 不存在,升级到 8.0 后若没补授,连接直接失败
  • CREATE TEMPORARY TABLES 在 8.0 是动态权限,但很多文档仍按老方式写成全局权限,导致 GRANT 语句报错 Unknown privilege
  • 复制账号(如用于 GTID 搭建)必须显式授予 REPLICATION SLAVE ADMIN,而非旧版的 REPLICATION SLAVE

权限回收后为什么应用还能查?

常见原因不是权限没生效,而是 MySQL 缓存了权限判断结果。执行 FLUSH PRIVILEGES 并不能解决所有情况 —— 它只刷新内存中的权限表副本,不影响已建立连接的会话权限。

真正生效的方式只有两个:

  • 让应用重连(最稳妥,尤其在容器/K8s 环境下滚动更新即可)
  • 对已存在的连接,执行 KILL CONNECTION 强制断开(需先查 SHOW PROCEsslIST

另一个隐蔽原因是:用户可能通过角色间接持有权限。比如你 revoke 了用户 A 的 SELECT,但他属于角色 R,而 R 仍有该权限。此时必须检查 SELECT * FROM mysql.role_edges WHERE TO_HOST = 'A',再针对性 revoke 角色权限。

权限最小化不是一次性配置,而是持续收敛的过程 —— 日志分析、角色审计、连接复用策略,每个环节都可能暴露过度授权。

text=ZqhQzanResources