MySQL 重置 root 密码,单看是个小主题,但这几年反而成了高频率踩坑的话题。原因是网上大量教程停留在 MySQL 5.6/5.7 时代,拿到 8.0 上照抄就出错;而 5.7 与 8.0 在用户表结构、密码插件、可用函数上都发生了变化。你经常看到的 UPDATE mysql.user SET authentication_string=PASSWORD('123456') WHERE User='root'; 在 5.7 里可能还跑得通,在 8.0 里会直接提示 FUNCTION mysql.PASSWORD does not exist。与其让新手在无数个错误命令之间来回试,不如把原理讲到能指导操作的程度。这篇文章把常见的丢失 root 密码场景、5.7 和 8.0 的差异、Linux 宿主机与 Docker 容器里的重置步骤都拆开讲,适合正在接管老库的运维同学,也适合刚部署完 MySQL 的初学者。
1. 动手前需要看清的:重置密码到底在改哪个 root
1.1 你遇到的场景可能比“忘了密码”更多
先说结论:所谓重置 root 密码,并不是每次都走同一条路。我实际处理下来,至少要区分以下几种情况。
第一种是真正忘记密码。这种情况最常见,手里可能有一些旧的连接串,但已经没人记得 root 密码是什么,任何登录都会报 Access denied for user 'root'@'localhost'。处理思路是临时绕过授权表登录,再重建密码。
第二种是安装完以后根本没设置过密码。用源码包或官方 tar 包安装时,MySQL 会在启动日志里生成一个临时密码,很多人顺手关掉终端就找不到了。这个时候不要急着 skip-grant-tables,先翻一下日志,往往一条命令就能解决:
bash复制grep 'temporary password' /var/log/mysqld.log
如果日志被轮转或清理,再尝试 grep -i 'password' /var/log/mysql/error.log。能找到临时密码,就省去一次重启。
第三种是密码没过期,但 root 账号被锁定,或者因为插件配置导致用密码总登不进去。尤其 Ubuntu 通过 apt 安装 MySQL 5.7 时,root 默认走 auth_socket 插件,你只知道密码却怎么都连不上,这种现象很容易被误判成“密码被篡改”。实际上你需要在 shell 里用 sudo mysql 直接进,进去后把认证插件改成 mysql_native_password 或 caching_sha2_password。
第四种场景常被忽略:Docker 容器初始化后,当初设置 MYSQL_ROOT_PASSWORD 时写了一个临时密码,后来容器换了机器重启,环境变量没有保留,密码自然就找不回来了。这种情况不能简单用宿主机上的重置习惯直接套。
1.2 MySQL 5.7 和 8.0 在认证机制上的分水岭
MySQL 5.7 和 8.0 都使用 mysql.user 表保存账号信息,但密码字段的处理逻辑差异非常大。
在 5.7 中,默认认证插件是 mysql_native_password,authentication_string 里保存的是类似 *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 这样的哈希值。旧的 PASSWORD() 函数仍然存在,所以老教程里那种直接 UPDATE mysql.user SET authentication_string=PASSWORD('xxx') 的方法确实能跑。但要注意,5.7 中如果 root 账号的 plugin 字段仍是 auth_socket,即使改了 authentication_string,密码也不会生效,因为 auth_socket 插件的认证逻辑根本不比对密码,而是直接检查当前操作系统用户名。
到了 8.0,事情变得更严格。默认认证插件切换为 caching_sha2_password,authentication_string 里保存的哈希以 $A$ 开头,这个哈希只能由服务端在设置密码时自动生成,你没法在客户端手工算出同样格式。另外,8.0 直接移除了 PASSWORD() 函数,任何尝试直接 UPDATE 密码哈希的做法要么报错,要么写入一段无意义的字符串,最终结果都是无法登录。
所以你现在只要看到网上教程里出现 PASSWORD(),基本就能判断那套方法来自 5.7 以前,不要原样拿到 8.0 上执行。
1.3 root 可能不止一个:localhost 与 % 的区别
重置前还要搞清楚一件事:MySQL 账号由 user 和 host 共同决定。root@localhost 和 root@'%' 是两个独立账号,各自有独立密码和认证插件。
