mysql权限应最小化:应用账号仅授必要库表操作权限,限定ip、禁用grant option、显式回收高危权限;强制tls加密传输,删除空用户,为用户启用require ssl;启用审计日志并推送至集中系统;定期轮换密码并回收闲置权限。

MySQL 用户权限最小化配置
直接给 root 或 application 用户 ALL PRIVILEGES 是最常见也最危险的起点。真实业务中,应用账号应只拥有它真正需要的库、表、操作类型——比如一个只读报表服务,SELECT 权限就够了,INSERT、DROP 必须显式拒绝。
实操建议:
- 用
CREATE USER 'app_rw'@'10.20.30.%' IDENTIFIED BY 'strong_pass_2024';明确限定 IP 段,避免'%'泛授权 - 用
GRANT SELECT, INSERT, UPDATE ON mydb.orders TO 'app_rw'@'10.20.30.%';精确到库+表,不带WITH GRANT OPTION - 执行
REVOKE DROP ON *.* FROM 'app_rw'@'10.20.30.%';(即使没授过,显式回收更稳妥) - 定期用
SHOW GRANTS FOR 'app_rw'@'10.20.30.%';核对,权限变更必须走审计流程
启用强制 TLS 并禁用匿名/空密码账户
明文传输账号密码等于把钥匙挂在 API 网关门口。MySQL 5.7+ 默认支持 TLS,但默认不强制;很多部署仍留着 ''@'localhost' 这类空用户名账户,是暴力扫描首选目标。
实操建议:
- 启动时加
--ssl-mode=REQUIRED,或在my.cnf中配置require_secure_transport = ON - 检查并删掉所有空用户:
DELETE FROM mysql.user WHERE User = '' OR authentication_string = '';,然后FLUSH PRIVILEGES; - 为每个业务用户指定
REQUIRE X509或至少REQUIRE SSL,例如:ALTER USER 'app_rw'@'10.20.30.%' REQUIRE SSL; - 确认连接是否真走 TLS:
SELECT Ssl_cipher FROM performance_schema.session_status WHERE VARIABLE_NAME = 'Ssl_cipher';返回非空值才算生效
审计日志 + 敏感操作拦截(MySQL Enterprise / Percona Server / MariaDB)
开源版 MySQL 社区版不自带审计功能,但 Percona Server 和 MariaDB 提供 server_audit 插件,MySQL Enterprise 则有 audit_log。没有审计,就等于没有录像——谁删了表、谁导出了百万用户手机号,全靠猜。
实操建议:
- Percona Server 启用:
INSTALL PLUGIN server_audit SONAME 'server_audit.so';,再设server_audit_logging=ON和server_audit_events='CONNECT,QUERY,TABLE' - 重点过滤高危语句:在应用层或代理层(如 ProxySQL)拦截含
DROP TABLE、SELECT ... INTO OUTFILE、LOAD DATA INFILE的请求 - 审计日志别存本地磁盘,用
server_audit_output_type=SYSLOG推送到集中日志系统(如 Loki + Grafana),防止被删库删日志一锅端 - 注意性能影响:审计日志 I/O 压力大,生产环境建议异步写入,且仅记录
ERROR级别或指定用户行为
定期凭证轮换与权限回收机制
“这个账号半年没动过,应该没问题”——这是安全事件前最常听到的话。权限不会自动过期,离职员工的账号可能还在连着核心库,测试环境密钥可能被硬编码进前端代码里。
实操建议:
- 所有密码设有效期:
ALTER USER 'app_rw'@'10.20.30.%' PASSWORD EXPIRE INTERVAL 90 DAY; - 用
SELECT user, host, password_last_changed FROM mysql.user WHERE password_last_changed 提前 10 天告警 - 每月跑一次闲置账号扫描:
SELECT user, host FROM mysql.user WHERE account_locked = 'N' AND password_last_changed - 禁止在配置文件里写明文密码;改用
mysql_config_editor存储加密登录路径,或通过 Vault 动态注入
真正难的不是加一堆开关,而是让权限变更、证书更新、日志归档这些动作变成自动化流水线的一部分。人工巡检永远漏得比补得快,而一个没被监控的 GRANT 语句,可能就是下一次数据泄露的起点。










