mysql本身不提供禁止用户修改自己密码的权限开关,仅能通过撤销create user等高权限或采用外部认证方式间接限制。

MySQL 本身没有禁止用户改自己密码的权限开关
直接说结论:ALTER USER、SET PASSWORD 这类操作,只要用户有 CREATE USER 或更高权限(比如 UPDATE 权限作用于 mysql.user 表),就能执行。MySQL 没提供类似 DENY ALTER USER 的语法,也没有 password_change_priv 这种细粒度权限。
所谓“禁止修改密码”,实际能做的只有两种路径:
- 撤掉用户的
CREATE USER权限(以及INSERT/UPDATE权限,如果它被直接赋在mysql库上) - 用外部认证方式绕过 MySQL 密码管理,比如 PAM 或 LDAP —— 此时密码根本不由 MySQL 存储或校验,自然无法从内部修改
注意:单纯 revoke UPDATE 权限对 mysql.user 表,**不一定生效**。因为 SET PASSWORD 和 ALTER USER ... IDENTIFIED BY 是专用语句,不走常规表更新路径,它们依赖的是全局权限而非具体表权限。
validate_password 插件不是“禁止”,而是“校验失败”
很多人误以为调低 validate_password_policy 就是“放开限制”,其实它只控制新密码是否被接受。哪怕你把策略设成 LOW,只要用户执行 ALTER USER 'u'@'%' IDENTIFIED BY '123',且当前 validate_password_length = 8,仍会报错:ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。
关键点:
-
validate_password插件默认只在创建用户、ALTER USER、SET PASSWORD时触发,不检查已存在的弱密码 - 它不区分用户角色——root 和普通用户一视同仁
- 即使你
REVOKE CREATE USER ON *.* FROM 'u'@'%',只要该用户之前有这个权限并没被刷新,仍可能成功改密(权限缓存未失效)
想真正锁死密码,只能靠外部认证或禁用相关语句
如果你控制着 MySQL 部署环境,且需要强约束(比如审计要求“密码由 IAM 统一管理”),可行做法是:
- 卸载
validate_password插件(UNINSTALL PLUGIN validate_password;),再启用可插拔认证,例如:CREATE USER 'u'@'%' IDENTIFIED WITH authentication_ldap_sasl AS 'uid=u,ou=people,dc=example,dc=com'; - 在数据库前置加代理层(如 ProxySQL),拦截含
ALTER USER、SET PASSWORD的语句并返回拒绝 - 用操作系统级限制:仅允许特定 IP 或跳板机连接,再配合数据库防火墙规则过滤敏感语法(需企业版或第三方组件)
直接改 mysql.user 表字段(比如清空 authentication_string)不可取——MySQL 8.0+ 已弃用 Password 字段,且手动 UPDATE 不触发权限重载,还容易破坏 hash 格式导致用户彻底无法登录。
flush privileges 不解决权限实时性问题
很多教程强调改完 mysql.user 表后必须 FLUSH PRIVILEGES,但这只对「通过直接写表方式授予权限」有效。而现代 MySQL 推荐用 GRANT/REVOKE,这些命令会自动刷新内存缓存,无需手动 flush。
更关键的是:FLUSH PRIVILEGES 并不会让一个已有连接立即失去刚被 revoke 的权限——它只影响后续新连接。也就是说,用户如果已经连着,他还能继续执行 SET PASSWORD 直到断开重连。
所以,真要阻断某用户改密行为,得结合连接管理:
- 查出该用户的活跃连接:
SELECT ID, USER, HOST, COMMAND FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'u'; - 强制踢下线:
KILL [ID]; - 再 revoke 权限,此时新连接就拿不到改密能力了
生产环境里,最常被忽略的其实是权限缓存延迟和连接长活问题——你以为权限已撤,其实用户还在旧会话里自由操作。











