
MySQL 8.0 上了 Windows 之后改密码这件事其实比 5.7 时代“讲究”多了。很多人还拿着老教程里的SET PASSWORD PASSWORD(xxx)去敲结果直接报错也有人忘了密码之后一顿瞎操作把整个服务搞得无法启动。这篇我就把 MySQL 8.0 在 Windows 下修改、重置用户密码这件事完整拆开覆盖“还能正常登录”和“彻底忘记密码”两种情况同时把 8.0 特有的认证插件、密码策略、配置文件位置、错误码等问题一并解决。适合 Windows 上跑 MySQL 8.0 的开发者和运维朋友照着操作基本不会翻车。1. MySQL 8.0密码体系的三个关键变化动手前先搞懂1.1 默认认证插件的更换直接影响了旧客户端MySQL 8.0 最明显的一个变化是默认认证插件从mysql_native_password换成了caching_sha2_password。这个改动对密码管理的影响非常大。老版本里你创建用户或者改密码默认走的是mysql_native_password客户端连接时只要做一次SHA1校验就可以而caching_sha2_password使用SHA256体系安全性更高但连接时会有一次“密码交换”过程非常旧的客户端和驱动如果没适配就会直接报 “Unable to load authentication plugin caching_sha2_password” 或者Authentication plugin caching_sha2_password cannot be loaded。对改密码这件事来说这意味着两件事。第一你用ALTER USER改完密码后账号的认证插件仍然是caching_sha2_password如果某个老程序连不上别上来就怀疑密码改错了大概率是客户端驱动版本太老。第二如果你确实需要兼容旧系统可以在改密码时顺手指定认证插件写成IDENTIFIED WITH mysql_native_password BY 密码。不过说实话mysql_native_password在 8.0 里已经被标记为过期能不用就不用升级客户端才是正路。1.2 PASSWORD()函数彻底移除老语法可能已失效如果你翻到一篇 5.6、5.7 时代的教程里面大概率会出现这一句SET PASSWORD PASSWORD(123456);在 MySQL 8.0 里执行这条你会直接得到类似ERROR 1305 (42000): FUNCTION mysql.PASSWORD does not exist的错误。因为PASSWORD()函数在 8.0 中被彻底移除了官方不希望你再用这种明文哈希方式去设置密码。MySQL 8.0 那里面的正确语法只有一个方向ALTER USER。也就是说如果看到“哪里教你把密码通过PASSWORD()函数处理后写进mysql.user表”的文章基本可以直接关掉了那套思路从 8.0 开始不仅麻烦而且已经完全不符合官方架构。1.3 从mysql.user表直接改密码不再可行ALTER USER是唯一正路在 5.7 及更早的版本里确实存在一条“野路子”直接UPDATE mysql.user SET authentication_stringPASSWORD(xxx) WHERE Userroot;然后再FLUSH PRIVILEGES。这套操作在 8.0 里基本是坑原因有三点PASSWORD()函数不存在没法直接生成合法的哈希字符串。8.0 的认证插件默认是caching_sha2_password它的哈希存储格式跟旧版完全不同手工拼字符串极易出错。直接改表很容易绕过密码过期管理、账户锁定状态等元数据导致之后出现各种奇怪行为。我见过有人硬改mysql.user表结果ALTER TABLE都不再生效需要重新初始化数据目录。所以这里先立一个原则只要是 MySQL 8.0修改密码就统一用ALTER USER不管你是正常登录时修改还是在忘密码之后恢复权限。2. 还能正常登录时的密码修改ALTER USER全流程2.1 修改当前账号密码的实际命令与细节如果你现在还能正常登录 MySQL修改密码其实一行 SQL 的事ALTER USER rootlocalhost IDENTIFIED BY 新密码;执行完之后不需要再FLUSH PRIVILEGESALTER USER会直接作用到授权系统并立即生效。但有三个细节我是踩过坑之后才注意到的。第一rootlocalhost这里的host必须写对。MySQL 的账号是由user host共同确定的。如果当初你是用root从远程%连进来的那你本地登录的账号可能是rootlocalhost也可能是root127.0.0.1。只改localhost不会影响%那个账号的密码反之亦然。所以当你说“我改了密码怎么还是旧的能登录”时先去查一下SELECT user, host, plugin, account_locked FROM mysql.user;把目标账号对应的host完全对上再改。第二如果你当前登录的用户并不是 root只是普通账号也可以修改自己的密码ALTER USER USER() IDENTIFIED BY 新密码;USER()函数返回当前会话的用户名和主机名这一条等价于修改当前登录账号。注意普通用户只能改自己的密码想改别人密码需要CREATE USER权限或者mysql库的相关权限否则会报权限不足。第三如果这个账号之前被设置了密码过期策略你修改密码之后还需要顺手确认一下过期状态。比如你登录时遇到ERROR 1820 (HY000)You must reset your password using ALTER USER statement before executing this statement那就说明账号密码已经过期必须在当前会话里先执行一次ALTER USER重设密码然后才能继续跑其他 SQL。ALTER USER rootlocalhost IDENTIFIED BY 新密码 PASSWORD EXPIRE NEVER;上面这句顺便把密码改为永不过期。如果你希望恢复默认过期策略就把PASSWORD EXPIRE NEVER换回PASSWORD EXPIRE DEFAULT。2.2 DBA视角批量修改与账户锁定状态检查如果你管理的是多个测试库或者多个业务账号偶尔会遇到“批量初始化密码”的场景。MySQL 8.0 没有一条命令能一次性改多个用户但你可以利用动态 SQL 拼出来SELECT CONCAT(ALTER USER , user, , host, IDENTIFIED BY 新密码;) FROM mysql.user WHERE user NOT IN (mysql.infoschema, mysql.session, mysql.sys);把查询结果导出后再执行。这里要特别提醒不要试图把所有系统内置账号也一起改了比如mysql.sys、mysql.session这些内部账户改了之后可能导致实例异常。另外我在实际维护中经常遇到的一种情况是账号没锁密码也没错但就是登不进去提示ERROR 3118 (HY000)Access denied for user rootlocalhost. Account is locked.这就不是密码问题而是账号被锁了。解决办法ALTER USER rootlocalhost ACCOUNT UNLOCK;所以在修改密码之后最好同时检查一下账号状态把密码修改、过期策略、锁定状态一次性处理好避免反复排查。2.3 新密码的立即验证方法改完密码后别急着关窗口一定要从“新会话”验证一次。由于ALTER USER生效是即时的你只要另开一个命令行窗口输入mysql -u root -p输入新密码能进就说明改成功了。这里有个经验之谈验证时尽量用 TCP 连接而不要用本机默认的命名管道或者 shared memory 方式避免出现“客户端连的是另外一套实例”之类的误会。mysql -u root -h 127.0.0.1 -P 3306 -p这样能确认端口、IP、账号密码都一致。3. 忘记密码后重置方案AWindows下skip-grant-tables完整抢救链路3.1 事前准备停止服务、定位配置文件、备份忘记密码后最直接的重置思路是“绕过权限检查”这就是--skip-grant-tables。但 Windows 上的操作细节比 Linux 多尤其要搞清楚服务名、配置文件路径和启动方式。首先找到你的 MySQL 服务名字。打开 PowerShell 或者 CMD执行sc query | findstr /i mysql一般会看到类似MYSQL80的服务名。如果是通过官方安装包安装的服务名通常就是MySQL80如果是自定义安装可能是MySQL、MySQL8.0之类的名字以你机器上的实际情况为准。然后需要找到my.ini配置文件。Windows 下最常见的路径是C:\ProgramData\MySQL\MySQL Server 8.0\my.ini注意ProgramData默认是隐藏目录需要在资源管理器里开启显示隐藏文件。如果是从压缩包解压后手动初始化的配置文件一般和解压目录同级比如D:\mysql-8.0.x-winx64\my.ini。找到了配置文件先复制一份备份到另一个地方比如my.ini.bak这一步非常重要后面恢复配置全靠它。3.2 加入skip-grant-tables并重启服务用记事本或任意编辑器打开my.ini在[mysqld]这一节下面加入[mysqld] skip-grant-tables然后停止 MySQL 服务net stop MySQL80再启动服务net start MySQL80这时候 MySQL 会以“跳过授权表”的模式运行任何客户端都可以不输入密码直接连接。如果你在启动过程中遇到“服务启动失败”或者“系统错误 1067”十有八九是my.ini里配置写错了或者当前已经有一个 mysqld 进程占着端口。先把进程清理干净再继续tasklist | findstr mysqld taskkill /F /IM mysqld.exe如果你不想改动my.ini也可以直接从命令行启动cd C:\Program Files\MySQL\MySQL Server 8.0\bin mysqld --skip-grant-tables --console但这种方式在 Windows 上有个缺点它会一直占据当前命令行窗口而且如果后面要重启服务得额外处理这个手工启动的进程。我更推荐改配置文件的方式因为恢复起来更可控。3.3 无密码进入后正确重置密码服务启动后直接打开一个新的 CMD 窗口建议管理员模式尝试无密码连接mysql -u root --skip-password能进入 MySQL 提示符就算成功。绝大部分教程到这里会直接让你执行ALTER USER但 8.0 有一个经典坑在skip-grant-tables模式下直接执行会报错ERROR 1290 (HY000)The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement。解决办法是先让授权系统恢复可用状态FLUSH PRIVILEGES;这句话并不会关闭跳过授权表模式但会重新加载权限表并允许当前会话执行ALTER USER。接下来就可以改密码了ALTER USER rootlocalhost IDENTIFIED BY 新密码;如果mysql.user里同时存在root的多个 host 记录比如rootlocalhost和root%建议逐一确认并修改SELECT user, host FROM mysql.user WHERE user root;然后分别执行ALTER USER。如果当前密码策略过于严格导致新密码设置失败可以在这一步临时降低策略或者使用满足强度要求的密码。策略调整方法我放在后面的报错章节这里先保证重置成功。3.4 恢复服务并验证新密码密码改完之后切记把my.ini里加的skip-grant-tables注释掉或删除然后重启服务net stop MySQL80 net start MySQL80如果少做这一步服务一直以跳过授权表模式运行等于所有人都可以免密连接这在任何环境下都是严重安全隐患。重启完成后用新密码连接验证一次mysql -u root -p能正常登录后再顺手确认一下密码策略和过期设置SHOW VARIABLES LIKE validate_password%; SHOW VARIABLES LIKE default_authentication_plugin;到这里方案 A 就算完整走通了。4. 忘记密码后重置方案Binit-file方式更稳更省事4.1 什么时候应该优先选择init-fileskip-grant-tables用起来直接但也存在几个让人头疼的问题一是需要手工编辑my.ini如果手滑删错了配置服务直接起不来二是修改完密码容易忘记删除这个参数导致服务长期处于免密状态三是有时候某些账号处于锁定状态skip-grant-tables模式下还需要额外处理。MySQL 8.0 提供了另一个同样官方的重置方法init-file 初始化脚本。它的原理是服务启动时会自动执行指定 SQL 文件里的语句。你不用无密码登录不用手工敲命令只要把ALTER USER写进文件里服务启动一次就自动完成密码重置。如果你的 MySQL 是作为 Windows 服务运行并且你觉得方案 A 的多步骤操作太容易漏掉一处方案 B 更稳妥。4.2 编写初始化脚本并配置my.ini在 C 盘根目录或者其他随意位置创建一个文本文件比如C:\mysql-init.txt内容如下ALTER USER rootlocalhost IDENTIFIED BY 新密码;注意文件里的语句必须以;结尾。如果要修改多个账号可以写多行。如果你不确定 root 的 host 是localhost还是%可以在文件里一起写比如ALTER USER rootlocalhost IDENTIFIED BY 新密码; ALTER USER root% IDENTIFIED BY 新密码;然后打开my.ini在[mysqld]下面加入一行init-fileC:/mysql-init.txt路径里的斜杠建议用正斜杠/避免反斜杠被当作转义字符引发解析问题。接下来停止、启动 MySQL 服务服务器就会在启动阶段自动执行这个文件里的 SQL。注意执行之后不会在控制台打印任何日志你要直接去验证密码。4.3 启动、验证与清理的完整流程服务启动成功后用新密码登录mysql -u root -p能进去就说明init-file里的语句已经生效。接下来最重要的一步把my.ini中的init-file那一行删掉或者注释然后再次重启服务否则每次 MySQL 启动都会执行这个文件等于你的密码每次都会被重置成脚本里那个新密码后续手工改密码也会被强行覆盖。如果登录失败请检查C:\ProgramData\MySQL\MySQL Server 8.0\Data目录下的.err错误日志文件里会记录init-file执行时遇到的 SQL 错误比如密码策略不满足、账号不存在等。根据日志提示修正 SQL 文件内容再启动一次即可。对比一下两种方案的特点其实很好选对比项skip-grant-tables 方案init-file 方案是否需要无密码连接需要不需要是否需要手工执行ALTER USER需要不需要自动执行忘记移除配置后的风险所有人可免密连接风险极高启动时自动重置密码风险中等但也可控定位问题难度低需要查错误日志适用性大多数忘记密码场景适合手滑之后反复出问题、或权限恢复时需要脚本化处理我个人的习惯是家里测试机用方案 A公司生产环境或者重要实例用方案 B。因为方案 B 的行为更确定启动一次后立刻清理配置不会留下“免密后门”。5. 重置密码后的高频报错与Windows环境避坑5.1 错误1819、1820、1290的场景与解决对照重置密码时最容易碰到的几个错误码我列一个对照表方便直接查询错误码典型信息出现场景解决方法ERROR 1045 (28000)Access denied for user rootlocalhost密码错误、账号不存在、host不匹配核对user/host确认当前所用密码服务排查锁账号ERROR 1819 (HY000)Your password does not satisfy the current policy requirements新密码不符合 validate_password 策略调整密码强度或临时降低 validate_password.policyERROR 1820 (HY000)You must reset your password using ALTER USER statement before executing this statement账号密码过期、首次登录引导状态登录后立即执行 ALTER USER 设置新密码ERROR 1290 (HY000)running with the --skip-grant-tables optionskip-grant-tables 模式下直接执行 ALTER USER先执行 FLUSH PRIVILEGES 再 ALTER USERERROR 3118 (HY000)Account is locked账号被锁定执行 ALTER USER rootlocalhost ACCOUNT UNLOCKERROR 3175Plugin caching_sha2_password is not loaded客户端/驱动不认识默认插件升级客户端驱动或临时将账号改为 mysql_native_password针对ERROR 1819如果你想临时降低密码策略可以在 MySQL 会话中执行SET GLOBAL validate_password.policy LOW; SET GLOBAL validate_password.length 6;这里要注意MySQL 8.0 默认安装中validate_password组件参数使用点号validate_password.policy而不是旧版的下划线validate_password_policy。如果你执行SHOW VARIABLES LIKE validate_password%;发现结果是空说明当前实例没有启用这个组件那就没必要调整密码策略不够严格时先正常设置即可。5.2 客户端版本过旧导致的caching_sha2_password连接失败重置密码成功后你可能会发现另一方带着老版本驱动连接时反而报错。这不是密码改坏了而是 8.0 默认插件caching_sha2_password和旧客户端的兼容问题。常见表现命令行客户端能连上程序报Authentication plugin caching_sha2_password cannot be loaded。解决方案有三个方向升级程序的 MySQL 驱动/客户端到支持caching_sha2_password的版本。对个别必须兼容旧端的账号显式指定老插件ALTER USER app% IDENTIFIED WITH mysql_native_password BY 新密码;在my.ini的[mysqld]下临时指定默认插件default_authentication_pluginmysql_native_password不过我非常不建议最后一种做法这会把整个实例的新账号全部拖回老认证方式而且该参数在 MySQL 8.0 里已经标记为过期。正确做法是升级驱动或者只对个别账号做兼容处理。5.3 Windows命令行引号转义与服务管理注意点最后聊聊 Windows 环境特有的几个“坑”这些不是 SQL 问题但最容易让人怀疑自己密码没改成功。第一密码里的特殊字符在 CMD 里容易被吞掉。比如你用这个命令连接mysql -u root -pPss!2024在 CMD 里会触发后台运行语义导致命令被截断!在某些环境里也有特殊解释。稳妥做法是密码不用引号直接交互式输入mysql -u root -p第二修改my.ini后如果服务启不来重点检查两件事my.ini是否被保存成了带 BOM 的 UTF-8 格式以及[mysqld]节下面是否有重复的配置项。BOM 会导致 MySQL 解析失败。第三如果服务启动时报系统错误 5基本是当前 CMD 没有管理员权限。务必右键“以管理员身份运行”之后再执行net stop、net start等命令。第四重置完密码后如果曾经用skip-grant-tables模式启动过服务建议在正常模式下执行一次FLUSH PRIVILEGES;然后再重启一次服务确保所有缓存中的权限状态都被清理干净。之前我在测试机上就是因为少了这一步新密码明明正确却偶尔出现旧会话还能继续操作的情况多花了不少时间排查。总的来说MySQL 8.0 在 Windows 上的密码管理核心就是两件事平时用明白ALTER USER应急时用对skip-grant-tables或init-file。我个人最推荐的做法是平时就做好my.ini备份并记录当前 root 账号的 host 到底是localhost还是%。真到忘记密码那天直接选择 init-file 方案改完配置重启一次就收工既不用在命令行里反复折腾授权状态也不会留下免密后门。最后再分享一个小技巧重置完密码之后第一时间在C:\ProgramData\MySQL\MySQL Server 8.0\Data目录下搜索最新的.err文件养成看错误日志的习惯。你会发现绝大多数所谓“改完密码登录不了”的诡异问题答案其实早就在日志里写明白了。