生产环境应遵循最小权限原则:按服务建专用账号(如shop_order_rw),仅授予必要库表的SELECT/INSERT/UPDATE/DELETE权限,禁用'%'主机名、root及系统账号,权限变更须走GRANT/REVOKE流程并纳入SQL变更审批。

只给最小必要权限,别用 GRANT ALL PRIVILEGES
生产环境里最常犯的错,就是建个账号顺手执行 GRANT ALL PRIVILEGES ON *.* TO 'appuser'@'%'。这等于把数据库当裸奔现场——一旦应用被注入或配置泄露,攻击者能删库、读取系统表、甚至写入文件(如果开了 FILE 权限)。
实操建议:
- 按模块/服务单独建用户,比如
shop_order_rw、report_ro,名字自带用途和权限范围 - 写操作只授
SELECT, INSERT, UPDATE, DELETE,且限制到具体库+表:GRANT SELECT, INSERT ON shop_db.orders TO 'shop_order_rw'@'10.20.30.%' - 读报表类账号一律加
WITH GRANT OPTION禁用,防止权限扩散 - 临时排查用的高权账号,设
MAX_QUERIES_PER_HOUR 0但必须配PASSWORD EXPIRE INTERVAL 1 DAY
慎用通配符主机名,优先绑定内网 IP 段
'user'@'%' 看着省事,实际等于开放所有网络入口。MySQL 默认不加密传输认证包(除非强制 REQUIRE SSL),中间人可截获密码哈希重放。
实操建议:
- 应用服务器固定 IP 的,直接写
'appuser'@'192.168.5.12';用 K8s 或云环境的,用 CIDR 段:'appuser'@'10.100.0.0/255.255.0.0' - 绝对不用
'%' + 密码弱策略组合。若必须用%,强制要求ALTER USER 'u'@'%' REQUIRE SUBJECT '/CN=app-server'做证书校验 - 测试环境也别图省事开
'%',本地开发用'localhost'(注意:它走 socket 连接,和127.0.0.1是两个用户)
避免用 root 或 mysql.sys 等内置账号跑应用
root 账号密码常被硬编码进配置文件或环境变量,一泄露就是全盘沦陷;mysql.sys 虽默认无密码,但拥有 INFORMATION_SCHEMA 和性能视图读取权,配合 SELECT ... INTO OUTFILE 可导出敏感元数据。
实操建议:
- 部署脚本里禁止出现
mysql -uroot -p...连接应用库,改用专用账号 - 检查
SELECT user, host FROM mysql.user,删掉所有host = '%'且user IN ('root', 'mysql.sys', 'debian-sys-maint')的行 - 用
SHOW GRANTS FOR 'appuser'@'10.20.30.%'定期审计,重点看是否意外继承了PROXY权限或CREATE USER
权限变更必须走 SQL 变更流程,禁用手工 FLUSH PRIVILEGES
直接改 mysql.user 表再刷权限,是 MySQL 最隐蔽的坑之一——表结构变更可能被复制中断、GTID 不一致,且 FLUSH PRIVILEGES 不会同步到从库。
实操建议:
- 所有权限增删改,统一走
GRANT/REVOKE语句,并纳入 DBA 审批的 SQL 变更单 - 自动化部署时,用
mysql -e "GRANT ..."而非先INSERT INTO mysql.user再FLUSH - 从库上执行
STOP SLAVE; SET sql_log_bin=0; GRANT ...; START SLAVE;属于高危操作,除非明确知道该权限仅用于从库监控
权限不是设一次就完事的事。MySQL 的 max_connections、wait_timeout 等资源限制参数,和权限策略一样影响安全边界——比如一个长期空闲的高权连接,可能成为未授权访问的跳板。真正难的是把权限逻辑嵌进 CI/CD 流程里,让每次应用发布自动校验账号权限是否收缩。










