外观
MySQL 密码策略与管理
密码验证插件
安装和启用密码验证插件
MySQL 5.7 及之前版本
sql
-- 安装validate_password插件
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
-- 查看插件状态
SHOW PLUGINS LIKE 'validate_password';
-- 查看插件变量
SHOW VARIABLES LIKE 'validate_password%';MySQL 8.0 及之后版本
sql
-- 安装validate_password组件
INSTALL COMPONENT 'file://component_validate_password';
-- 查看组件状态
SELECT * FROM mysql.component;
-- 查看组件变量
SHOW VARIABLES LIKE 'validate_password%';密码策略配置
密码复杂度要求
validate_password 插件参数
| 参数名称 | 说明 | 默认值 |
|---|---|---|
| validate_password_length | 密码最小长度 | 8 |
| validate_password_number_count | 密码中至少包含的数字个数 | 1 |
| validate_password_special_char_count | 密码中至少包含的特殊字符个数 | 1 |
| validate_password_mixed_case_count | 密码中至少包含的大小写字母个数 | 1 |
| validate_password_policy | 密码策略级别(0=LOW, 1=MEDIUM, 2=STRONG) | 1 |
| validate_password_dictionary_file | 密码字典文件路径 | 空 |
密码策略级别详解
| 策略级别 | 说明 |
|---|---|
| LOW | 只检查密码长度 |
| MEDIUM | 检查密码长度、数字、大小写字母和特殊字符 |
| STRONG | 检查密码长度、数字、大小写字母、特殊字符和字典文件 |
配置密码策略
临时配置
sql
-- 设置密码最小长度为12
SET GLOBAL validate_password_length = 12;
-- 设置密码策略为STRONG
SET GLOBAL validate_password_policy = 2;
-- 设置密码字典文件
SET GLOBAL validate_password_dictionary_file = '/path/to/dictionary.txt';永久配置
在MySQL配置文件中添加以下参数:
ini
[mysqld]
# 密码验证插件配置
validate_password_length = 12
validate_password_number_count = 2
validate_password_special_char_count = 1
validate_password_mixed_case_count = 2
validate_password_policy = STRONG
validate_password_dictionary_file = /path/to/dictionary.txt密码生命周期管理
密码过期策略
配置全局密码过期时间
sql
-- 设置全局密码过期时间为90天
SET GLOBAL default_password_lifetime = 90;
-- 禁用密码过期
SET GLOBAL default_password_lifetime = 0;在配置文件中添加:
ini
[mysqld]
default_password_lifetime = 90为特定用户设置密码过期时间
sql
-- 创建用户时设置密码过期时间为60天
CREATE USER 'user'@'host' IDENTIFIED BY 'password' PASSWORD EXPIRE INTERVAL 60 DAY;
-- 修改现有用户的密码过期时间
ALTER USER 'user'@'host' PASSWORD EXPIRE INTERVAL 60 DAY;
-- 禁用特定用户的密码过期
ALTER USER 'user'@'host' PASSWORD EXPIRE NEVER;
-- 遵循全局密码过期策略
ALTER USER 'user'@'host' PASSWORD EXPIRE DEFAULT;密码历史记录
启用密码历史记录
sql
-- 设置密码历史记录为5(用户不能重复使用最近5个密码)
SET GLOBAL password_history = 5;
-- 设置密码重用间隔为365天
SET GLOBAL password_reuse_interval = 365;在配置文件中添加:
ini
[mysqld]
password_history = 5
password_reuse_interval = 365为特定用户设置密码历史
sql
-- 创建用户时设置密码历史记录为10
CREATE USER 'user'@'host' IDENTIFIED BY 'password' PASSWORD HISTORY 10;
-- 修改现有用户的密码历史记录
ALTER USER 'user'@'host' PASSWORD HISTORY 10;用户密码管理
创建用户时的密码设置
sql
-- 创建用户并设置密码(自动哈希)
CREATE USER 'user'@'host' IDENTIFIED BY 'StrongPassword123!';
-- 使用特定认证插件创建用户
CREATE USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
CREATE USER 'user'@'host' IDENTIFIED WITH caching_sha2_password BY 'StrongPassword123!';修改用户密码
sql
-- 使用ALTER USER修改密码(推荐)
ALTER USER 'user'@'host' IDENTIFIED BY 'NewStrongPassword456!';
-- 使用SET PASSWORD修改密码(不推荐,MySQL 8.0中已弃用部分语法)
SET PASSWORD FOR 'user'@'host' = 'NewStrongPassword456!';重置密码
忘记root密码时的重置方法
停止MySQL服务
bashsystemctl stop mysqld以跳过授权表的方式启动MySQL
bashmysqld_safe --skip-grant-tables --skip-networking &登录MySQL并修改密码
sql-- 登录MySQL mysql -u root -- 切换到mysql数据库 USE mysql; -- 修改root密码 UPDATE user SET authentication_string = PASSWORD('NewRootPassword123!') WHERE User = 'root' AND Host = 'localhost'; -- MySQL 8.0使用以下命令 ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewRootPassword123!'; -- 刷新权限 FLUSH PRIVILEGES; -- 退出MySQL EXIT;重启MySQL服务
bashsystemctl restart mysqld
密码过期处理
sql
-- 手动将用户密码设置为过期
ALTER USER 'user'@'host' PASSWORD EXPIRE;
-- 查看密码过期状态
SELECT user, host, password_expired FROM mysql.user;
-- 用户登录时需要修改密码
mysql -u user -p
Enter password:
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
-- 修改过期密码
ALTER USER USER() IDENTIFIED BY 'NewPassword123!';密码安全最佳实践
密码策略最佳实践
设置强密码策略
- 密码长度至少12个字符
- 要求包含大小写字母、数字和特殊字符
- 使用STRONG密码策略级别
- 配置密码字典文件,防止使用常见密码
启用密码生命周期管理
- 设置密码过期时间(建议90-180天)
- 启用密码历史记录,防止密码重用
- 要求用户定期更换密码
使用安全的认证插件
- MySQL 8.0默认使用
caching_sha2_password,更安全 - 避免使用
mysql_old_password等不安全的认证插件 - 考虑使用外部认证插件(如LDAP、PAM)
- MySQL 8.0默认使用
用户管理最佳实践
最小权限原则
- 只为用户授予必要的权限
- 避免使用
GRANT ALL PRIVILEGES - 定期审核用户权限
用户命名规范
- 使用有意义的用户名,避免使用通用名称
- 包含用户角色或职责信息
- 例如:
app_read@'%'、admin_user@'localhost'
主机限制
- 限制用户的连接主机
- 避免使用
user@'%'(允许从任何主机连接) - 例如:
user@'192.168.1.0/24'、user@'localhost'
定期清理无用用户
- 删除不再使用的用户
- 禁用长期不活跃的用户
- 示例:sql
-- 删除用户 DROP USER 'user'@'host'; -- 禁用用户 UPDATE mysql.user SET account_locked = 'Y' WHERE user = 'user' AND host = 'host';
密码存储安全
避免明文存储密码
- 永远不要在配置文件、脚本或代码中明文存储密码
- 使用环境变量或密钥管理系统存储密码
- 示例:bash
# 使用环境变量 export MYSQL_ROOT_PASSWORD='StrongPassword123!' mysql -u root -p$MYSQL_ROOT_PASSWORD
加密存储密码文件
- 如果必须存储密码文件,使用加密方式
- 限制密码文件的访问权限
- 示例:bash
# 设置密码文件权限 chmod 600 ~/.my.cnf # 密码文件内容 [client] user = root password = StrongPassword123!
使用SSL/TLS加密连接
- 启用SSL/TLS加密,防止密码在传输过程中被窃取
- 配置
require_secure_transport = ON强制使用加密连接
密码审计与监控
审计密码策略合规性
sql
-- 查看所有用户的密码策略相关信息
SELECT
user,
host,
plugin,
password_expired,
password_last_changed,
password_lifetime
FROM mysql.user;
-- 查找使用弱密码的用户
SELECT user, host FROM mysql.user WHERE authentication_string = PASSWORD('123456');
-- 查找密码即将过期的用户(30天内)
SELECT
user,
host,
password_last_changed,
password_lifetime
FROM mysql.user
WHERE password_lifetime > 0
AND DATEDIFF(NOW(), password_last_changed) >= (password_lifetime - 30);监控密码相关事件
启用审计日志
ini[mysqld] plugin-load-add=audit_log.so audit_log_format=JSON audit_log_policy=ALL监控密码修改事件
- 使用Performance Schema监控密码相关语句
- 示例:sql
-- 启用语句事件监控 UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'; -- 查看密码修改语句 SELECT * FROM performance_schema.events_statements_history_long WHERE SQL_TEXT LIKE '%ALTER USER%IDENTIFIED BY%' OR SQL_TEXT LIKE '%SET PASSWORD%';
常见问题(FAQ)
Q1: 如何禁用密码验证插件?
A1: 可以通过以下方法禁用密码验证插件:
sql
-- MySQL 5.7及之前版本
UNINSTALL PLUGIN validate_password;
-- MySQL 8.0及之后版本
UNINSTALL COMPONENT 'file://component_validate_password';或者在配置文件中添加:
ini
[mysqld]
validate_password = OFFQ2: 如何处理应用程序无法满足强密码策略的情况?
A2: 如果应用程序无法生成符合强密码策略的密码,可以考虑以下方案:
- 调整密码策略为适合应用程序的级别
- 为应用程序用户创建专门的密码策略
- 考虑使用应用层密码管理,在应用层处理密码复杂度
- 使用API密钥或证书认证替代密码认证
Q3: MySQL 8.0 中的 caching_sha2_password 和 mysql_native_password 有什么区别?
A3: 主要区别:
| 特性 | caching_sha2_password | mysql_native_password |
|---|---|---|
| 安全性 | 更高,使用SHA-256算法 | 较低,使用SHA-1算法 |
| 性能 | 更好,支持缓存 | 一般 |
| 默认使用 | MySQL 8.0默认 | MySQL 5.7默认 |
| 客户端支持 | 需要较新的客户端 | 广泛支持 |
Q4: 如何批量修改用户密码?
A4: 可以使用以下方法批量修改用户密码:
sql
-- 创建存储过程批量修改密码
DELIMITER //
CREATE PROCEDURE batch_update_password()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE user_name VARCHAR(100);
DECLARE host_name VARCHAR(100);
DECLARE cur CURSOR FOR SELECT user, host FROM mysql.user WHERE user NOT IN ('root', 'mysql.sys', 'mysql.session', 'mysql.infoschema');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO user_name, host_name;
IF done THEN
LEAVE read_loop;
END IF;
-- 生成随机密码(实际使用中应使用更安全的随机密码生成方式)
SET @new_password = CONCAT('NewPass_', FLOOR(RAND() * 1000000));
SET @sql = CONCAT('ALTER USER ''', user_name, '''@''', host_name, ''' IDENTIFIED BY ''', @new_password, ''';');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 记录新密码(实际使用中应安全存储)
SELECT CONCAT('User: ', user_name, '@', host_name, ', New Password: ', @new_password) AS result;
END LOOP;
CLOSE cur;
END //
DELIMITER ;
-- 调用存储过程
CALL batch_update_password();Q5: 如何防止暴力破解密码?
A5: 防止暴力破解密码的措施:
启用密码失败次数限制
sql-- 设置连续失败5次锁定账户 SET GLOBAL max_connect_errors = 5;使用防火墙限制访问IP
bash# 使用iptables限制访问IP iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 3306 -j DROP启用双因素认证
- 使用第三方插件(如Google Authenticator)实现双因素认证
监控登录失败日志
bash# 监控登录失败日志 grep "Access denied" /var/log/mysqld.log
Q6: 如何迁移用户密码到新的认证插件?
A6: 迁移用户密码到新的认证插件的方法:
sql
-- 将用户从mysql_native_password迁移到caching_sha2_password
ALTER USER 'user'@'host' IDENTIFIED WITH caching_sha2_password BY 'StrongPassword123!';
-- 批量迁移所有用户
SELECT CONCAT('ALTER USER ''', user, '''@''', host, ''' IDENTIFIED WITH caching_sha2_password BY ''', authentication_string, ''';')
FROM mysql.user
WHERE plugin = 'mysql_native_password';Q7: 密码策略对性能有影响吗?
A7: 密码策略对MySQL性能的影响很小,主要在以下场景:
- 用户创建和密码修改时的密码复杂度检查
- 使用STRONG策略且配置了字典文件时,会增加密码检查时间
一般情况下,密码策略的性能影响可以忽略不计,建议优先考虑安全性。
Q8: 如何备份和恢复用户密码?
A8: 备份和恢复用户密码的方法:
bash
# 备份mysql.user表
mysqldump -u root -p mysql user > mysql_user_backup.sql
# 恢复mysql.user表
mysql -u root -p mysql < mysql_user_backup.sql
# 刷新权限
mysql -u root -p -e "FLUSH PRIVILEGES;"注意:
- 备份和恢复时要确保MySQL版本兼容
- 恢复后需要刷新权限
- 考虑使用
mysqlpump工具备份用户,它能更好地处理密码哈希
