业务账号权限最小化要求精确授予应用实际sql所需的表级权限并限制主机段,禁用grant option、all privileges on .、匿名用户及root远程访问,mysql 8.0+须用角色封装权限并设默认角色,列级权限用于敏感字段,grant后无需flush privileges但需set default role激活角色。

业务账号权限最小化不是“能连上就行”,而是让每个账号只拥有当前应用 SQL 实际执行所必需的那几条权限——多一条都算风险。
GRANT 语句必须精确到表和主机段
常见错误是 GRANT SELECT ON mydb.* TO 'app'@'%',它会把库下所有表(包括日志、配置、审计等敏感表)一并放开;更糟的是 '%' 允许任意 IP 连接,认证流量裸奔。
- 先确认应用真实访问的表:开
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.%' - 写操作账号也别贪全:
GRANT INSERT, UPDATE ON mydb.orders TO 'order_writer'@'10.20.30.%',不带DELETE就别加 - 主机段必须具体,
'10.20.30.%'比'%'安全得多;K8s 环境可用 CIDR:'app_user'@'10.100.0.0/255.255.0.0'
MySQL 8.0+ 必须用角色封装权限组合
直接给用户授予权限难维护,尤其当多个服务共用一类权限时。角色不是可选项,是批量管控的基础设施。
- 建角色:
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.%'; SET DEFAULT ROLE 'app_reader' TO 'webapp'@'10.20.30.%' -
SHOW GRANTS FOR 'webapp'@'10.20.30.%'看不到角色权限,得用SHOW GRANTS FOR 'webapp'@'10.20.30.%' USING 'app_reader'或登录后查CURRENT_ROLE()
绝对禁用的高危配置项
这些配置一旦存在,最小权限就形同虚设。
-
GRANT ... WITH GRANT OPTION:等于给了用户“转授权限”的能力,线上严禁出现 -
GRANT ALL PRIVILEGES ON *.*:包含DROP DATABASE、SHUTDOWN、FILE等高危权限,哪怕测试环境也不该用 - 匿名用户:
DROP USER ''@'localhost'必做,否则空用户名可无密码登录 - root 远程访问:
RENAME USER 'root'@'%' TO 'root'@'127.0.0.1',并确保skip-grant-tables在生产环境彻底关闭 - 列级权限虽少用,但处理身份证号字段时值得考虑:
GRANT SELECT (order_id, status) ON mydb.orders TO 'report'@'localhost'
权限生效与验证的关键细节
很多问题出在“以为授了权,其实没生效”。
-
GRANT后无需FLUSH PRIVILEGES(MySQL 5.7.6+ 和 8.0 默认立即生效),但若之前手动改过mysql.user表才需要刷 - 角色权限默认不激活,
SET DEFAULT ROLE是必须步骤,否则应用连接后CURRENT_ROLE()返回NULL - 新建用户默认只有
USAGE权限(即“能连但不能干任何事”),REVOKE不掉它,也不该碰它——只需GRANT显式需要的权限即可 - 认证插件不匹配会导致权限不触发:
mysql_native_password插件未加载时,即使GRANT正确,也会卡在认证阶段报错Plugin 'mysql_native_password' is not loaded
最常被忽略的点是权限继承关系:角色可以嵌套,但 REVOKE 不会级联;回收父角色权限后,子角色可能仍保留旧副本。上线前务必用真实账号连接,跑一遍业务 SQL,再查 INFORMATION_SCHEMA.ROLE_TABLE_GRANTS 或 SHOW GRANTS ... USING 做最终校验。











