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语句,可能就是下一次数据泄露的起点。
