必须用可审计、可回放、可自动化的机制固化权限流程,包括最小必要权限、时效控制、角色化管理、自动化回收与验证。

不能靠人工记账或口头约定,必须用可审计、可回放、可自动化的机制固化流程。 生产环境里一个没及时回收的测试账号,可能比弱密码更危险——它不触发告警,不产生日志异常,只等某次误操作或恶意利用时才暴露。真正的标准化,是让“谁在什么时候给谁授了什么权限、为什么授、有效期到哪天”全部可查、可验、可撤。
权限申请必须带明确作用域和时效
所有新权限申请,禁止出现 GRANT ALL PRIVILEGES 或 ON *.* 这类全局通配。审批系统(或工单模板)应强制填写:
- 目标数据库名(如
order_service),不允许填%或留空 - 最小必要权限组合(如仅
SELECT, INSERT,不含DELETE) - 主机白名单(如
'10.20.30.40'或'192.168.5.%',禁用'%') - 有效期(默认 7 天,超期自动失效;需延长必须重新走审批)
MySQL 本身不支持权限自动过期,所以必须靠外部流程控制——比如在工单系统中标记截止时间,并由运维脚本每日扫描 mysql.user 表中创建时间 + 主机信息,比对工单库里的有效期字段,发现超期立即 REVOKE 并告警。
授权操作必须绕过直接 GRANT,走预编译语句模板
运维人员不准手敲 GRANT 命令。所有授权必须调用内部封装的脚本或平台按钮,背后执行的是参数化 SQL:
CREATE USER IF NOT EXISTS ?@? IDENTIFIED WITH caching_sha2_password BY ?; GRANT ? ON ?.? TO ?@?; FLUSH PRIVILEGES;
其中每个 ? 都来自工单字段校验后的安全值。这样做的好处是:
- 避免手误把
app_user@'%'写成app_user@'%'(末尾空格导致权限不生效却无报错) - 防止绕过密码强度检查(脚本可集成
validate_password策略校验) - 每条执行记录自动落库到审计表,含操作人、时间、工单号、生成的完整 SQL
权限回收不是删用户,而是精准 REVOKE + 验证
离职、转岗、项目下线时,常见错误是直接 DROP USER ——这会连带删除该账号在所有库上的历史连接记录、性能统计、甚至监控埋点关联关系。正确做法是:
- 先
REVOKE ALL PRIVILEGES ON *.* FROM 'user_name'@'host' - 再
REVOKE GRANT OPTION ON *.* FROM 'user_name'@'host'(防止残留授权能力) - 最后验证:用该账号登录,执行
SHOW GRANTS,确认返回只有USAGE - 保留账号 90 天(仅禁用权限),用于追溯历史操作日志;超期后才
DROP USER
注意:REVOKE 不会自动刷新权限缓存,必须跟 FLUSH PRIVILEGES,否则旧权限仍可能生效数分钟——这点在高并发场景下极易被忽略。
角色(ROLE)不是可选项,而是生产环境强制基线
MySQL 8.0+ 的角色机制不是语法糖,它是解耦“身份”和“权限”的关键基础设施。生产环境必须做到:
- 每个业务系统对应一个角色(如
role_order_reader),权限只授予角色,不授给用户 - 用户通过
GRANT role_name TO 'user'@'host'绑定,且默认不激活(SET DEFAULT ROLE NONE) - 应用连接时显式执行
SET ROLE role_order_reader,否则只能用USAGE
这样一旦某个角色权限出问题,只需改角色定义,所有绑定用户即时同步;审计时查 mysql.role_edges 表,比遍历每个用户的 SHOW GRANTS 结果快十倍。而最容易被跳过的一步是:忘记执行 SET ROLE,导致应用连上却报 Access denied——因为没激活的角色等于没权限。



















