
先在前面说一下我遇到过的情况接手一台跑着 MySQL 8 的 Linux 服务器老同事交接文档里写着 root 密码是“root123”结果怎么都登不进去还有一次是测试环境配置好了就没管几个月后要用密码忘得一干二净。这种场景在运维和开发日常里太常见了。网上搜“Linux MySQL8 密码重置”能出来一堆答案但很多都是抄来抄去要么没讲清楚原理要么只给了跳过授权表的土办法注释配置的那一步忘了写安全隐患很大。这篇文章我把 Linux 下 MySQL 8 忘记 root 密码的几种重置方案都梳理一遍从原理到实操步骤再到重置后必须做的安全收尾一次性讲透。先明确一点MySQL 8 和 MySQL 5.7 在密码重置上有个关键差异——8.0 里PASSWORD()函数已经被移除默认认证插件也从mysql_native_password换成了caching_sha2_password。如果你还拿着 5.7 时期的旧思路用UPDATE mysql.user SET authentication_stringPASSWORD(xxx)这类命令去重置大概率会直接报错。所以这篇的重点是适配 MySQL 8 的正确姿势。1. 重置前先判断你是哪种“忘记密码”1.1 先分清是密码忘了还是密码策略问题很多人一上来就想着改配置、重启服务其实可以先冷静判断一下自己属于哪种情况。第一种情况是“刚接手别人的服务器”root 密码根本不知道。这时候最优先的动作不是强制重置而是去日志里翻初始密码。用 rpm 方式安装的 MySQL 8首次启动会在/var/log/mysqld.log里生成一个临时密码直接搜索就行grep temporary password /var/log/mysqld.log输出一般是这样的[Note] A temporary password is generated for rootlocalhost: 9iHd!kL2xQ拿到临时密码后登录MySQL 会强制要求先修改密码才能执行其他操作。第二种情况是自己的环境忘了密码那就可以直接进入后面的重置流程。还有一种容易被忽略的“假忘记密码”密码本身没错但客户端的字符集、SSL 配置或者caching_sha2_password插件和旧版客户端不兼容导致认证失败。判断方法很简单用命令行客户端直连试一次mysql -u root -p如果命令行能进只有程序连不上那问题大概率不在密码而是连接驱动或连接池配置的问题。这时候没必要重置密码排查方向应该转向驱动版本和连接参数。1.2 确认 MySQL 版本和认证插件重置之前建议先确认两件事MySQL 版本和 root 账号当前的认证插件。版本直接影响命令写法比如 MySQL 8.0.28 之后对密码策略的默认要求更高而 8.0.34 之后部分参数又有调整。查看版本mysql --version如果当前还能通过某种方式登录比如下面要讲的 auth_socket 方式可以顺便查一下账号信息SELECT user, host, plugin, authentication_string FROM mysql.user WHERE user root;plugin那一列的值决定了这个账号的认证方式。如果是auth_socket说明走的是 Unix Socket 认证系统用户和 MySQL 用户名一致就能免密码登录。如果是caching_sha2_password或mysql_native_password说明走的是密码认证忘记密码就必须用重置流程。1.3 重置前备份数据目录这一步很多人跳过但我强烈建议不要省。虽然重置密码理论上只改mysql.user表的数据但实际执行过程中如果误操作了mysql库里的其他表或者配置文件改错导致数据库启动失败数据丢失的风险是真实存在的。备份方式根据停机窗口来选择。如果可以短暂停机最直接的做法是把整个数据目录打包systemctl stop mysqld tar -czf /backup/mysql_datadir_$(date %F).tar.gz /var/lib/mysql systemctl start mysqld注意/var/lib/mysql是常见的数据目录位置有的环境配置在/data/mysql或者自定义路径先通过以下命令确认grep datadir /etc/my.cnf如果不能停机那就用逻辑备份mysqldump -u root -p --all-databases /backup/all_databases_$(date %F).sql即使是在权限混乱、密码已丢失的情况下也可以通过后面的 skip-grant-tables 模式连接数据库后再做逻辑备份。总之备份这一步是为了对冲操作风险尤其是生产环境宁可多花十分钟也不要裸奔操作。2. 方式一auth_socket 认证直接重置Ubuntu/Debian 系2.1 为什么 Ubuntu 上经常能直接 sudo mysql 进数据库如果你用的是 apt 方式安装的 MySQL 8在 Ubuntu 或 Debian 上root 用户默认走的是auth_socket认证。这个插件的工作逻辑和普通密码认证完全不同它不校验密码而是校验“发起连接的系统用户是谁”。当系统用户名为root且通过本地 socket 连接时MySQL 直接放行。这就是为什么很多教程里写着sudo mysql -u root可以直接进入 MySQL完全不需要密码。这个设计本意是提升安全性——只有系统 root 用户才能管理数据库 root 账号避免密码被暴力破解。但它的副作用就是当你想用密码登录 root 时反而会失败因为认证方式根本不是密码。这时不要以为密码忘了其实是 auth_socket 在生效。2.2 具体操作步骤和原理说明操作流程非常简单全程不需要重启 MySQL、不需要改配置文件也不会中断正在运行的服务。步骤只有四步# 第一步用系统 root 身份直接进入 MySQL sudo mysql -u root进入 MySQL 后执行-- 第二步将 root 的认证方式改为密码认证并设置新密码 ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY NewPassword2023; -- 第三步刷新权限 FLUSH PRIVILEGES;然后退出用密码验证exit mysql -u root -pALTER USER的IDENTIFIED WITH子句在这里起到了两重作用一是把auth_socket插件换成caching_sha2_password二是把密码设置进去。这里千万别用UPDATE mysql.user SET authentication_string...的旧方案因为authentication_string字段里存储的是哈希值不是明文直接UPDATE很容易把哈希值写坏导致认证彻底失效。2.3 这个小技巧有哪些坑需要注意第一个坑sudo mysql本身也进不去说明 root 账号不是 auth_socket 认证这个方法不适用。报错信息通常是Access denied for user rootlocalhost这时候跳过方式一用后面的通用方案。第二个坑新密码如果太简单会报ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。MySQL 8 默认开启了 validate_password 组件密码必须满足长度、大小写、数字和特殊字符的组合要求。建议直接设一个复杂度足够的密码比如Root2023#MySql这种省得还得临时调策略。第三个坑caching_sha2_password和旧客户端的兼容性。如果你的应用或者客户端工具只支持mysql_native_password比如一些老版本的libmysqlclient执行完上述命令后可能反而会导致应用连不上。这时候可以把认证插件改回mysql_native_passwordALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY NewPassword2023;虽然 MySQL 官方已经标记这个插件为废弃deprecated但在迁移过渡期用一下问题不大后续再慢慢升级客户端。3. 方式二skip-grant-tables 模式强制重置通用方案3.1 原理剖析为什么这个模式能绕过密码skip-grant-tables是 MySQL 提供的一个启动选项作用是在服务启动时不加载授权表。授权表就是mysql.user、mysql.db、mysql.tables_priv这些用来做权限校验的表格跳过加载意味着所有基于授权表的认证逻辑都不生效。最直接的结果就是任何用户都可以在不输入密码的情况下连接 MySQL并且拥有全部权限。这个选项是密码重置场景里的“万能钥匙”不管你是什么发行版、什么安装方式、root 账号什么插件统统能用。但它也是最需要谨慎使用的方式因为整个 MySQL 实例处于“裸奔”状态所以要严格控制操作窗口尽快完成重置并恢复正常认证模式。3.2 修改配置文件启动维护模式修改前先找到 MySQL 的主配置文件。RHEL/CentOS 系通常在/etc/my.cnfUbuntu/Debian 系通常在/etc/mysql/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf。不确定的话可以用my.cnf --help 2/dev/null | grep Default options -A 1或者直接看看哪个文件存在ls -l /etc/my.cnf /etc/mysql/my.cnf 2/dev/null编辑配置文件在[mysqld]段下新增一行skip-grant-tables注意必须放在[mysqld]段下面不能放在[client]或[mysql]段否则不生效。然后重启 MySQLsystemctl restart mysqld有的旧系统用的是 SysVinit 风格命令换成service mysql restart重启后再加一层保险确认服务确实起来了。systemctl status mysqld如果启动失败八成是配置文件格式有误或者[mysqld]段的位置不对回头检查。3.3 登录并重置密码的关键命令跳过授权表后登录完全不需要密码mysql -u root进入 MySQL 后如果没有任何提示就直接到了mysql命令行恭喜你已经进来了。接下来是重头戏这里有一个细节很多人不知道刚进入时是处于“未加载授权表”的状态直接执行ALTER USER大概率报错。先执行一次刷新授权表的操作让 MySQL 把授权表加载到内存FLUSH PRIVILEGES;然后再执行密码修改ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY NewPassword2023; FLUSH PRIVILEGES;为什么要先FLUSH PRIVILEGES因为skip-grant-tables模式下MySQL 的权限系统还在使用内部初始化的缓存数据没有读取mysql.user表此时执行ALTER USER会出现ERROR 1133 (42000): Cant find any matching row in the user table或者ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option。FLUSH PRIVILEGES会重新加载授权表让权限系统进入正常状态ALTER USER才能准确定位到 root 账号。这里还有个隐含的注意事项执行完第一次FLUSH PRIVILEGES之后MySQL 已经恢复了认证逻辑如果你此时断开连接再重新进入就不能再用无密码方式登录了。所以标准的操作顺序是登录 →FLUSH PRIVILEGES→ALTER USER→FLUSH PRIVILEGES→ 退出一气呵成中间不要断开。3.4 恢复正常的认证机制并验证重置完成后退出 MySQL 命令行exit接下来最关键的一步把配置文件里的skip-grant-tables那行注释掉或者直接删掉。这一步我见过太多人忘记导致 MySQL 长期运行在无认证状态等于把数据库裸奔在大街上。编辑/etc/my.cnf对应的位置加个#注释# skip-grant-tables然后重启 MySQLsystemctl restart mysqld用新密码验证登录mysql -u root -p输入刚才设置的密码能进入说明重置成功安全模式也正常退出了。3.5 这个方法里的几个实战细节第一个细节如果 MySQL 是通过 systemd 管理的修改配置文件后重启一定要用systemctl restart mysqld不要直接kill进程再手工启动否则 systemd 可能会在启动后自动检测异常并反复拉起反而造成混乱。第二个细节如果数据目录很大重启恢复可能需要较长时间socket连接会一直处于 waiting 状态别急着断定卡死看日志更靠谱tail -f /var/log/mysqld.log第三个细节也是最重要的skip-grant-tables状态下MySQL 会默认禁用远程 TCP 连接只允许本地连接这是官方的安全设计。但即使如此只要 MySQL 进程在跑本机上的任何用户都可以直接连接。所以在操作期间尽量别让其他无关人员登录这台机器。4. 方式三init_file 初始化脚本自动重置4.1 这个方式解决什么问题init_file方式适合的场景和 skip-grant-tables 不太一样。有时候你不想手工进入命令行操作比如服务器在远程、你正通过脚本批量处理多台机器或者你就是想让 MySQL 在启动时自动执行一条 SQL不多做多余动作。init_file就是 MySQL 启动时自动执行的 SQL 文件利用它来重置密码可以使流程自动化和脚本化。而且还有个好处它不需要进入skip-grant-tables那种“裸奔”模式MySQL 会正常加载授权表然后执行 SQL 文件中的命令。所以相对更安全整个重置过程可以比较优雅。4.2 配置和执行完整流程先创建一个 SQL 文件内容就是想要执行的密码重置语句vim /tmp/mysql-reset-password.sql写入ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY NewPassword2023;注意多条 SQL 用分号分隔不要写注释不要导入奇怪的字符。文件权限要确保 MySQL 进程能读取建议设为 600 并chown给mysql用户chmod 600 /tmp/mysql-reset-password.sql chown mysql:mysql /tmp/mysql-reset-password.sql然后在配置文件[mysqld]段下添加init_file/tmp/mysql-reset-password.sql重启 MySQLsystemctl restart mysqld重启完成后MySQL 会读取这个文件并逐条执行。然后验证mysql -u root -p能登录说明init_file里的 SQL 执行成功了。最后清理现场删掉临时 SQL 文件注释掉配置里的init_file行再次重启。这一步千万别漏否则以后每次重启都会执行那个文件如果文件里的 SQL 有副作用比如持续修改密码会把密码搞乱。4.3 init_file 的坑路径、权限和日志排查如果重启后新密码没生效首先检查 MySQL 的错误日志tail -50 /var/log/mysqld.log或者tail -50 /var/log/mysql/error.log常见的问题包括文件路径写错配置里写的和实际放的根本不是一个位置、文件权限不足导致 MySQL 进程无法读取、SQL 语法错误比如少了分号或者把ALTER USER写成了UPDATE。还有一个隐蔽问题init_file中的 SQL 如果执行失败MySQL 可能不会阻止启动但密码不会变也不会有明显报错只能靠翻日志来定位。4.4 三种方式的选型对比方案是否需要重启是否需要改配置操作复杂度适用场景auth_socket 重置否否低Ubuntu/Debian 系系统 root 能直接进入 MySQLskip-grant-tables是是中通用性最强适合各种发行版和安装方式init_file 重置是是中需要自动化、无人值守或不想手工交互我的建议是如果你的环境支持 auth_socket能sudo mysql直接进去优先用方式一零停机、零配置变更、操作安全。如果不支持那就用 skip-grant-tables虽然要重启但最可靠、最通用。init_file适合写脚本批量处理多台机器单机操作其实没必要上这个方案。5. 重置后的安全检查与常见问题速查5.1 重置后别急着走先做个全面确认密码改完后建议不要直接退出跑路花两分钟做一次确认。查看 root 账号的状态SELECT user, host, plugin, authentication_string FROM mysql.user WHERE user root\G重点看两个地方plugin是否为caching_sha2_password或mysql_native_passwordauthentication_string是否非空。如果plugin是auth_socket且你想用密码登录说明刚才方式一的ALTER USER没有真正执行成功如果authentication_string为空说明密码没设置上。然后顺手验证一下远程和本地的连接差异。本地用 socket 连接mysql -u root -p如果应用需要远程连接还要确认 MySQL 的bind-address配置是否允许对应 IP 访问。默认值往往是127.0.0.1只允许本地连接如果业务需要后续单独处理。5.2 常见错误速查表错误现象原因解决方案ERROR 1045 (28000): Access denied输入的密码不对或 auth_socket 插件仍在拦截确认是否走错认证方式尝试 sudo mysql 进入后重新 ALTER USERERROR 1819 (HY000): password does not satisfy policy密码强度不够未满足 validate_password 策略设置包含大小写、数字、特殊字符的长密码或临时调整密码策略ERROR 1133 (42000): Cant find any matching row in the user tableskip-grant-tables 模式下未先执行FLUSH PRIVILEGES登录后先FLUSH PRIVILEGES;再执行ALTER USERERROR 1290 (HY000): server is running with --skip-grant-tables权限表未加载ALTER USER 被限制先FLUSH PRIVILEGES;再执行 ALTERERROR 1396 (HY000): Operation ALTER USER failedroot 账号的主机名不匹配写成root%但实际是rootlocalhost先SELECT user, host FROM mysql.user WHERE userroot;确认准确写法MySQL 启动失败配置文件写错、数据目录权限异常、SELinux 拦截查看/var/log/mysqld.log确认datadir权限必要时调整 SELinuxsystemctl restart mysqld 超时数据量大InnoDB 恢复耗时太长不要立刻杀掉进程继续观察日志耐心等待5.3 重置后的安全收尾动作密码重置完成后有几个收尾动作不能省。第一确认配置文件里没有残留的skip-grant-tables或init_file配置。这俩都是用完就要删的留着就是定时炸弹。第二如果刚才在/tmp下创建过 SQL 文件、脚本文件已经没用了立刻删除。第三如果这台服务器的 3306 端口暴露在公网或对部分办公网段开放建议用防火墙收紧访问来源密码只是第一道防线网络层控制同样重要iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP第四如果应用层配置了连接池比如 Spring Boot HikariCP、Node.js 的 mysql2 pool这些连接池里缓存了旧密码的连接重置密码后旧连接不会自动重建应用仍会报连接错误。这种情况通常需要重启应用服务或者等连接池内部的连接淘汰机制触发重建。所以别奇怪“密码明明改对了应用怎么还是报错”。我处理过一次线上事故就是数据库管理员改了密码但应用没重启导致大面积连接报错排查了半天才发现是连接池缓存了旧连接。5.4 后续建议如何避免再次忘记密码密码管理是个老生常谈的问题这里给点实际的建议。一是新建账号时区分管理账号和业务账号不要所有应用都共用 root。二是使用密码管理工具记录密码哪怕只是 KeePassXC、Bitwarden 这类本地工具也比在群里发明文强。三是 MySQL 的 validate_password 组件保持开启不要为了图省事把它关掉它对密码强度是有实际价值的。四是定期审计账号权限。最后分享一个小技巧如果你手头有多台服务器且都是 MySQL 8密码重置的操作完全可以写成 Ansible 剧本或 Shell 脚本。核心思路是生成临时 SQL 文件 → 修改配置 → 重启 → 验证 → 清理现场。脚本里多做一步“验证新密码”的动作如果没有通过就自动回滚配置恢复原状这样即使操作失误也不会把数据库搞到不可用。写得好的话整个重置过程可以控制在两分钟以内从“密码遗忘”到“恢复生产”的全流程都会顺畅很多。