.mysql_history文件会明文记录含密码的SQL操作,因是客户端本地文件且不被服务端脱敏,比服务端日志更危险;应删除并软链至/dev/null或设MYSQL_HISTFILE=/dev/null禁用。

MySQL 历史记录文件(.mysql_history)默认会明文保存所有交互式执行的 SQL 语句,包括 CREATE USER、SET PASSWORD、GRANT ... IDENTIFIED BY 等含密码的操作——这是生产环境最常被忽略的密码泄露源之一。
为什么 .mysql_history 比日志更危险?
MySQL 服务端日志(如 general log、binary log)对含 IDENTIFIED BY 的语句做了自动脱敏(重写为 IDENTIFIED WITH ***),但 .mysql_history 是客户端本地文件,完全不经过服务端处理。只要用户用 mysql -u root -p123456 连过库,密码就直接落在该文件里,且权限通常为 600 ——看似安全,实则只要同一系统上有提权能力的其他用户(或恶意进程),就能读取。
常见错误现象:
- 审计扫描工具报出“
.mysql_historycontains plaintext credentials” -
ps aux | grep mysql曾暴露过命令行密码,而历史文件是它的“持久化副本” - 运维人员交接账号时,误把整个
$HOME打包迁移,连带泄露历史密码
如何立即清理并永久禁用 .mysql_history?
不能只删文件,必须阻断后续写入。两种方式任选其一,推荐后者:
- 删除当前文件并创建指向
/dev/null的符号链接:rm -f $HOME/.mysql_history && ln -s /dev/null $HOME/.mysql_history - 设置环境变量让客户端跳过记录:
echo 'export MYSQL_HISTFILE=/dev/null' >> /etc/profile && source /etc/profile
注意:MYSQL_HISTFILE 在 MySQL 5.7+ 生效;若用旧版本(如 5.6),仅靠环境变量无效,必须用符号链接方式。
哪些操作仍会导致密码明文落地?怎么规避?
即使关了 .mysql_history,以下行为依然危险:
- 在 shell 脚本中硬编码
mysql -u user -ppassword——ps可见,且脚本本身可能被误传或备份 - 使用
MYSQL_PWD环境变量 —— 全局可见,env | grep MYSQL_PWD就能抓到 - 直接
INSERT INTO mysql.user更新authentication_string字段 —— 此类语句不被服务端脱敏,会原样进 general log
正确做法:
- 改用
mysql_config_editor存储加密凭据:mysql_config_editor set --login-path=prod --user=app_user --password --host=10.0.1.5 - 连接时用
mysql --login-path=prod,既免输密码又无明文痕迹 - 绝对避免在 SQL 语句中拼接密码字符串,尤其是应用层动态构造的
CREATE USER
审计时容易漏掉的三个隐藏位置
检查完 .mysql_history,别急着收工。这些地方同样存有明文密码,且常被自动化审计工具忽略:
-
/root/.bash_history或普通用户家目录下的.zsh_history—— 里面可能有带-p参数的mysql命令 -
/etc/my.cnf或/etc/mysql/conf.d/下的配置文件 —— 若存在[client]段落并写了password=xxx,等同于明文存储 - 数据库备份脚本(如
/backup/mysql-dump.sh)—— 很多团队把mysqldump -u root -pXXX写死在定时任务里
真正安全的审计不是“查一个文件”,而是确认所有路径上没有可被非授权用户读取的、含 -p、PASSWORD、password= 的文本行。哪怕是一次性调试脚本,也得清干净。











