很多人在 CentOS 9 上忘记 MySQL 密码后,第一反应是重装或者重新初始化。这个思路风险很大,因为真正会损坏现有数据库的,通常不是“改密码”本身,而是误执行了初始化命令、误删了数据目录、或者把服务起到了错误的数据目录上。
这篇文章介绍两种做法:
- 推荐方案:
--init-file
- 备用方案:
--skip-grant-tables
如果你的目标是“只重置密码,不影响现有库表数据”,优先使用第一种。
一、先说结论
在 CentOS 9 上,MySQL 8.0 一般由 systemd 管理,服务名通常是 mysqld,常用命令如下:
sudo systemctl status mysqld
sudo systemctl stop mysqld
sudo systemctl start mysqld
sudo systemctl restart mysqld
忘记密码时,最重要的原则是:
- 不要执行
mysqld --initialize
- 不要删除
/var/lib/mysql
- 不要改错
datadir
- 不要直接手工改
mysql.user 表字段
- 优先使用
ALTER USER
二、修改前先确认两件事
先确认服务是否正常,以及当前配置文件里是否定义了数据目录:
sudo systemctl status mysqld
sudo grep -R "^datadir" /etc/my.cnf /etc/my.cnf.d 2>/dev/null
which mysqld
如果你担心误操作,建议先做一份物理备份:
sudo tar -czf /root/mysql-backup-$(date +%F-%H%M%S).tar.gz /var/lib/mysql
这一步不是必须,但非常建议。
三、推荐方案:使用 --init-file 重置密码
这个方法的优点是暴露面更小,只在启动时执行一条 SQL,安全性比 --skip-grant-tables 更好。
1. 停止 MySQL 服务
sudo systemctl stop mysqld
2. 创建初始化 SQL 文件
把下面的 新密码 改成你自己的密码:
sudo tee /tmp/mysql-init <<'EOF'
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
EOF
sudo chmod 600 /tmp/mysql-init
sudo chown mysql:mysql /tmp/mysql-init
如果你不仅有 root@localhost,还有 root@127.0.0.1、root@::1 或其他 Host,也可以写成多行:
sudo tee /tmp/mysql-init <<'EOF'
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '新密码';
ALTER USER 'root'@'::1' IDENTIFIED BY '新密码';
EOF
sudo chmod 600 /tmp/mysql-init
sudo chown mysql:mysql /tmp/mysql-init
3. 用初始化文件启动 MySQL
sudo mysqld --user=mysql --init-file=/tmp/mysql-init --console
说明:
- 这里不要加
--initialize
- 建议先前台启动,这样出错能直接看到日志
- 如果启动成功,执行完 SQL 后保持运行是正常的
4. 新开一个终端测试登录
mysql -uroot -p
输入你刚设置的新密码。
5. 清理临时文件并恢复 systemd 管理
如果已经验证登录成功,就回到原终端结束临时实例,或者直接另开终端执行:
sudo pkill mysqld
sudo rm -f /tmp/mysql-init
sudo systemctl start mysqld
再次验证:
mysql -uroot -p
四、备用方案:使用 --skip-grant-tables 重置密码
这个方法也常见,但安全性更差。MySQL 官方文档明确说明,这种方式“less secure”。在这种模式下,权限系统暂时被绕过,本地风险更高,所以只建议在临时维护时使用。
1. 停止服务并清理残留进程
sudo systemctl stop mysqld
sudo pkill mysqld
ps -ef | grep [m]ysqld
确保没有残留 mysqld 进程。
2. 以前台方式启动免权限实例
sudo mysqld --skip-grant-tables --skip-networking --user=mysql --console
说明:
--skip-grant-tables 表示跳过权限校验
--skip-networking 可以进一步降低暴露面
- 建议不要直接
& 放后台,否则失败了不容易发现
3. 新开一个终端连接 MySQL
mysql
如果能进入 MySQL,再执行:
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
注意,MySQL 8.0 下先执行 FLUSH PRIVILEGES;,再执行 ALTER USER,这是官方推荐的顺序。
如果你还有其他 root 账号,也可以逐个修改:
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '新密码';
ALTER USER 'root'@'::1' IDENTIFIED BY '新密码';
如果不确定有哪些账号,可以先查:
SELECT user, host FROM mysql.user ORDER BY user, host;
4. 退出并恢复正常服务
exit
sudo pkill mysqld
sudo systemctl start mysqld
mysql -uroot -p
五、为什么有时执行了 --skip-grant-tables 还是报 1045?
这个情况很常见,通常不是 SQL 有问题,而是下面几种原因:
- 新的
mysqld 实例根本没有成功启动
- 旧的
mysqld 进程没有退出,客户端连到的还是原服务
- socket 文件或 PID 文件冲突,导致临时实例启动失败
- 命令放后台后报错没看到
排查方法:
ps -ef | grep [m]ysqld
sudo tail -n 100 /var/log/mysqld.log
如果是免权限实例,最稳妥的启动方式还是:
sudo mysqld --skip-grant-tables --skip-networking --user=mysql --console
这样报错会直接显示在当前终端里。
六、如何把多个 Host 的 root 账号都改成同一个密码?
先查看 root 账号有哪些 Host:
SELECT user, host FROM mysql.user WHERE user='root';
然后按实际结果逐个执行:
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
ALTER USER 'root'@'127.0.0.1' IDENTIFIED BY '新密码';
ALTER USER 'root'@'::1' IDENTIFIED BY '新密码';
如果只是为了本机登录,一般改这几个就够了。
不建议轻易设置:
ALTER USER 'root'@'%' IDENTIFIED BY '新密码';
因为 root@'%' 表示允许任意来源远程登录,安全风险非常高。除非你明确知道自己在做什么,否则不要开。
七、最容易踩坑的地方
mysqld --initialize 会初始化数据目录,不是改密码命令
- 删除
/var/lib/mysql 会直接导致数据库丢失
- 在 CentOS 9 上服务名通常是
mysqld,不是 mysql
--skip-grant-tables 模式下要先 FLUSH PRIVILEGES
- 不要直接
UPDATE mysql.user ...,MySQL 8.0 优先使用 ALTER USER
- 如果前台启动报错,优先看
/var/log/mysqld.log
八、建议采用哪种方案?
如果是生产环境或者你特别在意“不能破坏现有数据库”,建议:
- 先备份
/var/lib/mysql
- 优先使用
--init-file
- 只有在
--init-file 不方便时,才使用 --skip-grant-tables
我的建议是:
--init-file 更适合写进正式教程,--skip-grant-tables 更适合作为备用排障方案。
九、命令速查版
推荐方案:
sudo systemctl stop mysqld
sudo tee /tmp/mysql-init <<'EOF'
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
EOF
sudo chmod 600 /tmp/mysql-init
sudo chown mysql:mysql /tmp/mysql-init
sudo mysqld --user=mysql --init-file=/tmp/mysql-init --console
新开终端测试:
mysql -uroot -p
恢复:
sudo pkill mysqld
sudo rm -f /tmp/mysql-init
sudo systemctl start mysqld
备用方案:
sudo systemctl stop mysqld
sudo pkill mysqld
sudo mysqld --skip-grant-tables --skip-networking --user=mysql --console
新开终端执行:
mysql
进入后:
FLUSH PRIVILEGES;
ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';
恢复:
sudo pkill mysqld
sudo systemctl start mysqld
参考资料