ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL 8.0密码策略报错1819:validate_password机制与生产实践

MySQL 8.0密码策略报错1819:validate_password机制与生产实践 刚装完 MySQL 8.0很多人第一件事就是拿 root 登上去改密码。我这些年看过不少现场在 5.7 里一路顺畅的123456换到 8.0 直接给你甩一条ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。如果你也被这句话卡住先别急着怀疑键盘——这是MySQL 8.0 默认密码策略在起作用。这篇文章不打算只教你怎么复制粘贴命令而是想把这个策略的前因后果、本地开发和生产环境分别该怎么处理以及我从安装、配置到卸载重装踩过的连环坑一次性讲透。无论你是刚入门的运维新人还是被测试环境反复折磨的开发照着这篇文章的思路走基本都能顺利过关。1. 为什么123456这种密码在 8.0 里会直接吃一个 18191.1 先看报错现场我用 Windows 上最常见的安装路径举例。假设你已经通过 MySQL Installer 装好了 MySQL 8.0服务名为MySQL80命令行工具在C:\Program Files\MySQL\MySQL Server 8.0\bin下。首次登录是拿安装过程中生成的临时密码进去的很多教程都会让你紧接着执行ALTER USER rootlocalhost IDENTIFIED BY 123456;然后屏幕上就出现那句经典的报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements这句话翻译过来就是你的密码不满足当前策略要求。注意它没有告诉你还差几位数字缺不缺大写字母这是 MySQL 的懒人作风——只丢一个笼统的错误码剩下全靠你猜。我看过有人因为这个报错反复重装 MySQL也有人直接怀疑是安装包有问题其实都不是就是策略没搞明白。1.2 5.7 到 8.0从插件到组件默认策略到底谁在管在 MySQL 8.0 里真正管密码强度的是validate_password这套机制。它最早是 5.7 时代的插件plugin到了 8.0 后变成了组件component官方从 8.0.27 开始引入组件形态从 8.0.34 开始官方安装包默认就把它装上了。这解释了一个让很多人疑惑的现象同样是 8.0隔壁同事的机器设123456没问题你的机器就报 1819。差别很可能在于你用的是 8.0.34 以后的官方安装包初始化完组件默认就在运行同事用的是旧版本或者他早前手动卸载过组件你们走的是不同的安装渠道比如 Windows MSI、Linux RPM、Docker 镜像默认行为的细节完全不同。另外有个非常普遍的误解MySQL Installer 安装过程中那个强密码要求是安装器自己的校验不是服务器策略在生效。很多人因此在安装器里被迫输了一个超复杂的密码就误以为服务器默认策略也是它设定的。实际上装完之后服务器里到底有没有跑validate_password需要用命令自己确认。1.3 检查当前策略的最快姿势别急着猜先上命令。用 root 登录后一次执行这三条SELECT * FROM mysql.component; SHOW PLUGINS; SHOW VARIABLES LIKE validate_password%;第一条能看到已经安装的组件里面有component_validate_password就说明组件在第二条能看到插件列表里有没有validate_password第三条最直接能查出当前实际生效的策略参数。如果第三条返回一堆validate_password.xxx变量说明策略正在运行那么你设简单密码必然撞墙如果返回空结果说明当前压根没有密码校验报 1819 就得换个方向排查。我把这三条命令当作病前三查无论帖子、文档里怎么说先确认机器实际状态永远是第一步。2. 默认策略的解剖validate_password 的规则、等级和判定逻辑2.1 三个等级一条长度红线validate_password的策略policy分三档理解它比背参数重要得多等级数值强制条件LOW0只检查密码长度MEDIUM1长度 数字 大小写混合 特殊字符STRONG2MEDIUM 全部要求 字典文件检查8.0 的默认策略是MEDIUM。也就是说在默认情况下一个密码要同时满足长度不低于validate_password.length默认 8、包含至少 1 个数字、至少 1 个小写字母、至少 1 个大写字母、至少 1 个特殊字符。这几乎断了所有省事密码的活路。我经常用一句话给刚接触的人概括LOW 是只卡长度MEDIUM 是五大门槛全要过STRONG 还要防你把单词当密码。后面两档的规则还能通过参数调整但这个等级结构是所有判断的基础。2.2 参数一览与默认值组件模式下的变量名都是validate_password.参数名这种带点号的格式和 5.7 插件时代的validate_password_参数名下划线格式不一样写配置文件的时候千万别混。常见的几个参数默认值如下变量名默认值含义validate_password.policyMEDIUM策略等级validate_password.length8密码最小长度validate_password.mixed_case_count1至少包含的大小写字母数量同时要求有小写和大写validate_password.number_count1至少包含的数字数量validate_password.special_char_count1至少包含的特殊字符数量validate_password.check_user_nameON密码不能包含用户名这里有个容易误会的点mixed_case_count 1不是只要有一个字母即可而是必须同时存在至少一个大写字母和至少一个小写字母。5.7 时代这个参数叫validate_password_mixed_case_count含义一样但现在很多人翻老教程时对着新旧两种变量名来回试搞到怀疑人生。2.3 一个密码是怎么被判死刑的拿MEDIUM默认参数举例子。假设你输入123456长度 6低于默认长度 8不通过只有数字没有大小写字母不通过没有特殊字符不通过。一条密码死在三个条件上MySQL 却只回你一个 1819毫无提示量。再看Abc#1234长度 8达标包含数字1、2、3、4达标包含小写b、c和大写A达标包含特殊字符#达标。所以它在默认策略下可以通过。整个判定过程是一票否决制任何一个条件不满足就整体拒绝不存在什么加权平均。知道这一点你就能理解为什么网上那些加个!就能过的说法其实是碰巧凑齐了条件。2.4 check_user_name 这个隐藏坑很多人没注意到validate_password.check_user_name默认是ON意思是密码不能包含当前的用户名。假设你是root用户设root123这种密码就算长度和复杂度全达标也会因为包含了root直接报 1819。有一次我在一台测试机上眼睁睁看着一个同事对着密码调了半天大小写加够了、特殊字符也有了就是忘了密码里带了自己的用户名。判断逻辑是按字符串包含关系比较的不区分大小写所以ROOT、Root、root都不行。要临时关掉可以执行SET GLOBAL validate_password.check_user_name OFF但我建议尽量别关换个思路给用户起一个不容易写进密码的用户名更省心。2.5 字典检查的 STRONG 到底多烦STRONG等级在MEDIUM的基础上还会检查字典文件也就是validate_password.dictionary_file指向的单词列表。密码不能是字典里现成的单词比如Password123这种常见组合如果字典文件里有password照样会被拒绝。实际工作中用STRONG的场景很少它主要出现在等保要求严格的政企环境里。日常开发完全用不上但你要知道它存在免得在某个客户环境里看到一个dictionary_file变量不知道是什么。3. 本地开发环境改简单密码从临时放行到永久放行的完整操作3.1 动手之前先确认两件事本地开发机、测试环境想用简单密码这是完全合理的需求没什么好羞耻的。但动手之前先确认两件事第一当前策略确实是validate_password在拦你用前面说的三条命令查一遍第二想清楚你要的是临时放行一次还是以后每次重启都放行。这两个目标的操作路径完全不同很多人就是没想清楚改完当时能设密码了重启之后又打回原形然后开始怀疑人生。我给的默认建议是本地开发用降级到 LOW 放宽长度方案而不是彻底卸载组件。理由后面讲。3.2 方案一把策略降到 LOW推荐假设你已经用临时密码登录或者已经改好了一个强密码目标是把 root 密码改成123456。按顺序执行SET GLOBAL validate_password.policy LOW; SET GLOBAL validate_password.length 6; FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY 123456;这里有两个关键点都是踩过的坑只降policy LOW还不够。LOW 仍然要检查length默认值是 8而123456只有 6 位所以你只降策略不降长度还是会被 1819 拦下来。我见过太多人卡在这一步以为LOW 就是啥都能设。SET GLOBAL是运行时设置不写进配置文件的话MySQL 服务一重启就恢复默认。如果你希望重启后策略依然宽松需要在my.iniWindows或my.cnfLinux的[mysqld]段里追加[mysqld] validate_password.policyLOW validate_password.length6注意变量名要用点号格式。加了配置后重启服务再用SHOW VARIABLES LIKE validate_password%确认一下别想当然。3.3 方案二彻底卸载 validate_password 组件如果你追求一了百了可以卸载组件UNINSTALL COMPONENT file://component_validate_password;执行完以后validate_password系列变量全部消失之前那套强度校验彻底下线再执行ALTER USER ... IDENTIFIED BY 123456就不会有任何阻拦。将来想恢复执行INSTALL COMPONENT file://component_validate_password;组件卸载是持久化的写入的是mysql.component系统表不依赖服务重启状态。为什么不把卸载组件作为首选方案两个原因。第一卸载是全局性的你以后万一要在这个实例里建测试账号、模拟生产环境密码策略全没了容易养成坏习惯第二有些团队规范或后续排查工具会默认校验validate_password变量是否存在组件没了反而多出一些解释成本。降级到 LOW 已经能设简单密码没必要把整套机制拆掉。3.4 放行之后的恢复动作如果是临时放行比如只是想改个密码然后继续用强策略那么改完之后记得恢复SET GLOBAL validate_password.policy MEDIUM; SET GLOBAL validate_password.length 8;这个操作同样只影响当前运行实例重启后如果my.ini里写的是LOW那还是会以配置文件为准。所以要想清楚恢复到底恢复到哪里。也有人图省事把my.ini里那两行策略参数永久写成LOW然后只在应用层约束自己这在纯本地的开发机上我能理解但一旦这台机器暴露到内网甚至公网风险就完全变了下面专门聊生产环境。4. 生产环境别照抄策略松绑的最小代价与替代思路4.1 为什么生产环境不要整体降级本地开发怎么折腾都行生产环境我只有一个态度默认策略别动尤其是别卸载 validate_password 组件。这不是教条而是现实考虑。首先策略是全局的MySQL 8.0 没有只对某个账号放宽密码策略的原生选项。你以为只是给一个老业务账号开了绿灯实际上所有账号的密码门槛一起降了包括 DBA 的 root、备份账号、监控账号。出现弱密码问题的时候审计甩过来的清单上可不会只列那一个账号。其次生产环境的历史负担往往很重。今天你把策略降成 LOW明天某个同事顺手建了个Admin123的业务账号后天一台数据库被扫到弱口令最后背锅的还是当初做这个决定的人。我在线上见过太多类似事故几乎都是临时为了图方便开始以紧急整改结束。还有一个容易被忽略的点如果你在生产环境装了validate_password然后又卸载某些自动化巡检脚本会告警缺少密码强度组件这会产生大量无效告警把真正重要的告警淹没掉。4.2 为老应用单账号开绿灯的折中方案我知道现实里有不得不让步的时候比如老应用写死了密码改密码要动代码发版而发版窗口排到下个月。这种场景下我的折中方案是能不降级就不降级。先算算老应用用的密码能不能凑到 8 位 数字 大小写 特殊字符很多时候目标密码只差一两个字符完全可以在应用配置里同步调整。必须降级时守住底线。至少保持policy LOW且length 12只允许长度门槛但把长度拉高。这样至少能拦住大量随手输入的弱口令扫描。从网络层补漏。密码弱了就用访问控制补限制该账号只允许白名单 IP 连接、只授权业务库的最小权限、禁用远程 root 登录、开启插件日志留痕。弱密码 公网可达 全库权限是生产事故的三大标配任何一个都得堵上。发版后第一时间恢复。把降低策略当作战时状态记到变更单里排期恢复别让临时变成永久。我习惯在变更单里写明2024-xx-xx 临时降低策略预计恢复时间到期前一周提醒相关同事。4.3 除了强度还有密码过期和失败锁定密码强度只是账号安全的一半另外两件事经常被一起漏掉。密码过期策略由default_password_lifetime控制默认值是 0表示密码永不过期。生产环境建议设置default_password_lifetime 90让账号定期改密也可以针对单个账号单独设置ALTER USER app_user% PASSWORD EXPIRE INTERVAL 90 DAY;另一个是连续失败锁定社区版里通常用connection_control插件实现。它可以在同一账号连续多次登录失败后强制插入延迟甚至临时拒绝连接能有效对抗暴力破解。安装和启用并不复杂但很多人装机时根本不知道有这个东西。4.4 认证插件是另一个容易被误伤的环节和生产环境密码相关的还有一件事不是策略本身但经常和它一起爆发8.0 默认的认证插件是caching_sha2_password老版本的客户端、旧版 JDBC 驱动、某些老管理工具连不上报错千奇百怪最典型的是Authentication plugin caching_sha2_password cannot be loaded一个常见操作是把账号改回老的mysql_native_password认证ALTER USER app_user% IDENTIFIED WITH mysql_native_password BY Some#Strong1;注意这个命令里的密码同样要过validate_password的检查所以 8.0 里很多改了认证插件还是报 1819的提问本质是密码本身没过策略不是认证插件的问题。另外mysql_native_password自 8.0.34 开始被官方标记为废弃8.4 里默认禁用所以新项目更推荐直接升级客户端和驱动而不是回头用老插件。5. 避坑实录从临时密码到远程连接那些连环坑5.1 首次登录的临时密码和 expired 状态8.0 安装完以后root 账号会生成一个临时密码。Windows 上它可能出现在安装器界面也可能在错误日志里。我用 ZIP 包手工安装时最常去这里找C:\ProgramData\MySQL\MySQL Server 8.0\Data\主机名.errLinux 上一般是grep temporary password /var/log/mysqld.log拿到临时密码登录后账号处于密码过期expired状态。这个状态下你几乎只能执行改密码相关的语句其他所有操作都会报ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.很多人第一步直接执行SET GLOBAL validate_password.policy LOW想先放行再改密码结果被 1820 弹回来然后开始绕圈子。正确顺序是先用临时密码登录立刻把它改成一个合规的强密码比如Temp#2024Abc退出重新登录这时候再执行SET GLOBAL validate_password.policy LOW、SET GLOBAL validate_password.length 6最后再ALTER USER rootlocalhost IDENTIFIED BY 123456。流程确实是绕了一圈但这是 MySQL 的机制所致顺序反了就走不通。5.2 组件卸载后装不回去两个常见误操作第一个误操作是重复安装。有些人先执行UNINSTALL COMPONENT发现变量还在于是又执行一次INSTALL COMPONENT结果报组件已存在之类的错误。其实第一次UNINSTALL如果执行时提示成功但SHOW VARIABLES还能查到变量这通常是当前会话之前的缓存或者连接池里旧连接的状态新开一个连接再查就干净了。别急着反复卸载安装先断开会话确认。第二个误操作更隐蔽卸载组件后my.ini里还留着validate_password.policyLOW这样的配置。下次重启服务加载配置时发现validate_password这个变量不存在直接拒绝启动。Windows 上表现为服务启动失败、事件查看器里记录一条 unknown variable 错误。解决方法是把配置文件里的相关行删掉。所以我一直提醒改配置要配套卸载组件时记得清配置安装组件时记得加配置。5.3 Docker 里 MYSQL_ROOT_PASSWORD 设弱密码失败用 Docker 跑 MySQL 8.0 的人越来越多官方镜像通过环境变量MYSQL_ROOT_PASSWORD设置 root 密码。很多人在本地随手写environment: MYSQL_ROOT_PASSWORD: 123456结果容器初始化失败看日志发现同样是 1819。原因和裸装一模一样官方镜像的初始化流程会启动一个临时 MySQL 实例来执行初始化 SQL如果这个实例加载了validate_password弱密码就会被拦。我建议的几种处理方式如果只是本地联调先用一个合规的初始化密码容器起来之后再进容器执行降级策略并改成简单密码或者挂载一个配置文件到/etc/mysql/conf.d/zz-policy.cnf内容写[mysqld]下的validate_password.policyLOW和validate_password.length6在首次初始化前就生效再或者利用/docker-entrypoint-initdb.d/目录挂载一个.sql脚本在初始化阶段先执行SET GLOBAL再执行ALTER USER。这里要特别留意这些方法只对首次初始化空数据目录时有效。如果你的docker volume已经初始化过了再改环境变量和配置文件都不会重建 root 密码需要手动进容器改。5.4 配置文件里写了策略参数但服务起不来这个坑在 Linux 上很典型。你用的是 5.7 时代的老教程往my.cnf里写了validate_password_policyLOW注意这是下划线格式对应的是旧插件变量。8.0 的组件变量是点号格式validate_password.policy。如果当前实例装的是组件而不是旧插件下划线格式的变量名服务器不认直接启动失败。反过来如果你是按点号格式写的但当前实例的组件没安装同样也会因为 unknown variable 起不来。所以每当你改完my.cnf服务起不来第一反应应该是删掉刚加的行而不是反复重启。等实例能正常启动了再想清楚变量格式对不对、组件装没装这两个问题。5.5 卸载重装后的策略残留Windows 上卸载 MySQL 重装是高频操作但很多人不知道mysql.component表存在数据目录里。你用控制面板卸载了安装器、删了C:\Program Files\MySQL\MySQL Server 8.0但如果数据目录没清干净重装时新实例可能会继承旧状态包括已安装的组件、旧账号、旧密码策略。更常见的是反过来数据目录删了重建组件回到出厂状态配置文件却还在结果新实例起不来或者起来了但密码策略和你预期的不一样。我处理这种问题时的固定步骤是先停服务、备份数据、彻底删除ProgramData下的数据目录、清空配置文件里的策略相关行、再重装。顺序不能乱否则就是各种灵异现象。6. 实操层面的个人建议把这几年和validate_password反复纠缠的经验浓缩成几句话。第一本地开发机用 LOW length6 这个组合就够了别直接卸载组件。保留组件意味着你随时可以切回 MEDIUM 模拟生产环境的行为而不用重新装一遍。第二所有策略变更都要留痕。我在本地和测试机上都会在my.ini里写注释标明这行是哪个需求、什么时候加的、什么时候可以删。看起来像是小题大做但当你三个月后在一台陌生的机器上排查 1819 时这段注释就是救命稻草。第三改完策略一定要验证。执行SHOW VARIABLES LIKE validate_password%确认当前值再开一个新会话测试登录不要在一个会话里一条龙操作完就以为万事大吉。我在 Docker 里多次遇到当时能登录、重建容器就废的尴尬就是吃了没验证的亏。第四密码策略只是入口不是全部。就算本地开发密码设成123456也记得关掉远程 root 登录、限制监听地址、随时准备销毁重建。开发机最大的价值就是可以随时推倒重来既然密码已经弱了其他防护就尽量别省。最后分享一个很实用的检查思路每次碰到 1819先问自己三个问题——当前实例到底有没有装validate_password当前策略是哪个等级我改的是运行时变量还是配置文件三个问题查一遍90% 的密码坑都能原地解决剩下的 10% 基本就是 Docker 数据目录或重装残留这些场景照着上面第五节的内容也能定位。
返回列表