Skip to content

MySQL 访问控制规范

访问控制基础

访问控制流程

MySQL的访问控制分为两个阶段:

  1. 连接验证阶段

    • 验证客户端IP地址、用户名和密码
    • 检查用户是否被授权从该主机访问
    • 检查用户账户是否被锁定或密码是否过期
  2. 请求验证阶段

    • 验证用户是否有权限执行请求的操作
    • 检查用户是否有权限访问请求的数据库和表
    • 检查用户是否有权限执行特定的SQL语句类型

权限层级

MySQL权限分为以下层级:

  • 全局权限:适用于所有数据库和表
  • 数据库权限:适用于特定数据库中的所有表
  • 表权限:适用于特定表
  • 列权限:适用于表中的特定列
  • 存储程序权限:适用于存储过程、函数和触发器

用户管理规范

用户命名规范

命名规则

  • 用户名应具有描述性,反映用户的用途或所属系统
  • 避免使用默认用户名(如root)
  • 避免使用特殊字符和空格
  • 区分大小写(在Linux系统上)

示例

  • 应用程序用户:app_erpapp_crm
  • 只读用户:readonly_reportreadonly_analytics
  • 管理用户:admin_dbaadmin_monitor

用户创建规范

创建用户时的必填信息

  • 用户名
  • 主机名(或IP地址)
  • 强密码
  • 必要的权限

创建用户的SQL语法

sql
-- MySQL 8.0+
CREATE USER 'username'@'host' IDENTIFIED BY 'strong_password';

-- MySQL 5.7及以下
CREATE USER 'username'@'host' IDENTIFIED BY 'strong_password';

示例

sql
-- 创建应用程序用户
CREATE USER 'app_erp'@'192.168.1.%' IDENTIFIED BY 'MyS3cur3P@ssw0rd!';

-- 创建只读用户
CREATE USER 'readonly_report'@'%' IDENTIFIED BY 'R3@d0nlyP@ss!';

密码管理规范

密码复杂度要求

  • 至少8个字符
  • 包含大小写字母
  • 包含数字
  • 包含特殊字符
  • 避免使用常见密码

密码策略配置

sql
-- 启用密码验证插件
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- 配置密码策略
SET GLOBAL validate_password_policy = 'STRONG';
SET GLOBAL validate_password_length = 12;
SET GLOBAL validate_password_number_count = 2;
SET GLOBAL validate_password_special_char_count = 2;

密码过期策略

sql
-- 设置密码过期时间(90天)
ALTER USER 'username'@'host' PASSWORD EXPIRE INTERVAL 90 DAY;

-- 禁用密码过期
ALTER USER 'username'@'host' PASSWORD EXPIRE NEVER;

用户锁定规范

自动锁定

sql
-- 连续失败登录5次后锁定账户
SET GLOBAL max_connect_errors = 5;

手动锁定/解锁

sql
-- 锁定用户
ALTER USER 'username'@'host' ACCOUNT LOCK;

-- 解锁用户
ALTER USER 'username'@'host' ACCOUNT UNLOCK;

权限管理规范

最小权限原则

定义:只授予用户完成其工作所需的最小权限

实施方法

  • 避免授予全局ALL PRIVILEGES
  • 根据用户角色分配特定权限
  • 定期审查和回收不必要的权限

示例

sql
-- 错误:授予过多权限
GRANT ALL PRIVILEGES ON *.* TO 'app_user'@'%';

-- 正确:只授予必要权限
GRANT SELECT, INSERT, UPDATE, DELETE ON erp.* TO 'app_erp'@'192.168.1.%';
GRANT SELECT ON reporting.* TO 'readonly_report'@'%';

权限分配策略

按角色分配权限

角色权限适用用户
应用程序用户SELECT, INSERT, UPDATE, DELETE业务应用连接用户
只读用户SELECT报表、分析用户
DBA用户ALL PRIVILEGES数据库管理员
监控用户PROCESS, REPLICATION CLIENT, SELECT监控系统用户
备份用户SELECT, LOCK TABLES, SHOW VIEW, RELOAD, REPLICATION CLIENT备份系统用户

权限授予规范

权限授予语法

sql
-- 授予数据库级权限
GRANT SELECT, INSERT, UPDATE, DELETE ON database.* TO 'user'@'host';

-- 授予表级权限
GRANT SELECT, UPDATE ON database.table TO 'user'@'host';

-- 授予列级权限
GRANT SELECT (column1, column2), UPDATE (column1) ON database.table TO 'user'@'host';

-- 授予存储程序权限
GRANT EXECUTE ON PROCEDURE database.procedure TO 'user'@'host';

刷新权限

sql
-- 刷新权限缓存
FLUSH PRIVILEGES;

权限回收规范

权限回收语法

sql
-- 回收数据库级权限
REVOKE DELETE ON database.* FROM 'user'@'host';

-- 回收所有权限
REVOKE ALL PRIVILEGES ON *.* FROM 'user'@'host';

注意事项

  • 回收权限后需要刷新权限缓存
  • 回收权限时要小心,避免影响业务运行
  • 定期审查用户权限,回收不必要的权限

访问控制列表(ACL)规范

主机名规范

使用IP地址而非主机名

  • 避免DNS解析失败的风险
  • 提高安全性,防止DNS欺骗

使用通配符的最佳实践

  • 只在必要时使用通配符
  • 避免使用%通配符(允许所有IP访问)
  • 限制通配符的范围,如192.168.1.%

示例

sql
-- 允许特定IP访问
CREATE USER 'app'@'192.168.1.100' IDENTIFIED BY 'password';

-- 允许特定网段访问
CREATE USER 'app'@'192.168.1.%' IDENTIFIED BY 'password';

-- 允许本地访问
CREATE USER 'app'@'localhost' IDENTIFIED BY 'password';
CREATE USER 'app'@'127.0.0.1' IDENTIFIED BY 'password';

网络访问控制

防火墙配置

  • 只允许特定IP或网段访问MySQL端口(默认3306)
  • 在应用服务器和数据库服务器之间配置防火墙规则
  • 定期审查防火墙规则

Linux防火墙示例

bash
# 允许特定IP访问3306端口
iptables -A INPUT -s 192.168.1.100 -p tcp --dport 3306 -j ACCEPT

# 允许特定网段访问3306端口
iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 3306 -j ACCEPT

# 拒绝其他所有IP访问3306端口
iptables -A INPUT -p tcp --dport 3306 -j DROP

云平台安全组配置

  • 在AWS、阿里云等云平台上配置安全组规则
  • 只允许特定IP或安全组访问MySQL端口
  • 定期审查安全组规则

特殊用户管理

Root用户管理

安全建议

  • 避免直接使用root用户连接数据库
  • 限制root用户的访问主机(仅允许localhost或特定管理IP)
  • 为root用户设置强密码
  • 定期更换root密码
  • 避免在应用程序中使用root用户

配置示例

sql
-- 确保root用户只能从localhost访问
DELETE FROM mysql.user WHERE User='root' AND Host!='localhost' AND Host!='127.0.0.1';
FLUSH PRIVILEGES;

Anonymous用户管理

安全建议

  • 删除所有匿名用户
  • 匿名用户可能导致安全漏洞

删除匿名用户

sql
-- 删除匿名用户
DELETE FROM mysql.user WHERE User='';
FLUSH PRIVILEGES;

Test数据库管理

安全建议

  • 删除默认的test数据库
  • test数据库可能被用于未授权访问测试

删除test数据库

sql
-- 删除test数据库
DROP DATABASE IF EXISTS test;
-- 删除test数据库的权限
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;

访问控制监控与审计

监控用户活动

启用审计日志

ini
# MySQL 8.0+
[mysqld]
plugin_load_add = audit_log.so
audit_log_format = JSON
audit_log_policy = ALL

# MySQL 5.7及以下
# 需要安装第三方审计插件,如Percona Audit Log Plugin

监控连接情况

sql
-- 查看当前连接
SHOW PROCESSLIST;

-- 查看连接统计
SHOW GLOBAL STATUS LIKE 'Connections';
SHOW GLOBAL STATUS LIKE 'Aborted_connects';

-- 查看用户权限
SHOW GRANTS FOR 'username'@'host';

定期权限审查

审查频率

  • 每月审查一次用户权限
  • 每次系统变更后审查相关权限
  • 每季度进行一次全面权限审计

审查内容

  • 检查是否有不必要的权限
  • 检查是否有过期的用户
  • 检查是否有异常的用户活动
  • 检查是否有违反最小权限原则的用户

自动审查脚本示例

sql
-- 查找具有全局ALL PRIVILEGES的用户
SELECT user, host FROM mysql.user WHERE Super_priv='Y';

-- 查找具有危险权限的用户
SELECT user, host FROM mysql.user WHERE 
  Grant_priv='Y' OR 
  File_priv='Y' OR 
  Shutdown_priv='Y' OR 
  Process_priv='Y' OR 
  Super_priv='Y';

-- 查找允许所有主机访问的用户
SELECT user, host FROM mysql.user WHERE host='%';

访问控制最佳实践

1. 实施强密码策略

  • 启用密码验证插件
  • 设置密码复杂度要求
  • 定期强制密码更换
  • 禁止使用弱密码

2. 限制远程访问

  • 只允许必要的IP或网段访问MySQL
  • 避免使用通配符%
  • 配置防火墙规则
  • 使用SSH隧道或VPN进行远程访问

3. 实施角色分离

  • 不同角色使用不同的用户
  • 区分读写权限
  • 区分管理权限和普通权限

4. 定期备份权限

  • 定期备份mysql数据库
  • 记录所有权限变更
  • 建立权限变更审批流程

备份mysql数据库

bash
mysqldump -u root -p mysql > mysql_grants_backup.sql

5. 启用SSL/TLS加密

  • 配置MySQL使用SSL/TLS加密连接
  • 强制客户端使用SSL连接
  • 定期更新SSL证书

配置SSL/TLS

ini
[mysqld]
ssl_ca = /path/to/ca.pem
ssl_cert = /path/to/server-cert.pem
ssl_key = /path/to/server-key.pem
require_secure_transport = ON

访问控制故障排除

常见访问控制问题

1. 访问被拒绝(Access denied)

原因

  • 用户名或密码错误
  • 主机名不允许访问
  • 权限不足
  • 密码过期
  • 账户被锁定

解决方案

sql
-- 检查用户是否存在
SELECT user, host FROM mysql.user WHERE user='username';

-- 检查用户权限
SHOW GRANTS FOR 'username'@'host';

-- 检查密码过期情况
SELECT user, host, password_expired FROM mysql.user WHERE user='username';

-- 检查账户锁定情况
SELECT user, host, account_locked FROM mysql.user WHERE user='username';

2. 权限不生效

原因

  • 没有刷新权限
  • 权限授予错误
  • 用户连接的主机名与授权主机名不匹配

解决方案

sql
-- 刷新权限
FLUSH PRIVILEGES;

-- 检查用户实际连接的主机名
SELECT user, host FROM information_schema.processlist WHERE ID=CONNECTION_ID();

-- 检查权限授予情况
SHOW GRANTS FOR 'username'@'actual_host';

3. 连接数过多

原因

  • 应用程序连接泄漏
  • 连接池配置不当
  • 恶意攻击

解决方案

sql
-- 查看当前连接数
SHOW GLOBAL STATUS LIKE 'Threads_connected';

-- 查看最大连接数
SHOW GLOBAL VARIABLES LIKE 'max_connections';

-- 查看连接状态
SHOW PROCESSLIST;

-- 终止异常连接
KILL CONNECTION connection_id;

版本差异考虑

MySQL 5.7 vs MySQL 8.0的访问控制差异

特性MySQL 5.7MySQL 8.0
用户创建语法CREATE USER 'user'@'host' IDENTIFIED BY 'password';相同,但增加了更多密码验证选项
密码哈希算法mysql_native_password(默认)caching_sha2_password(默认)
角色管理不支持支持角色管理
密码验证插件validate_password(可选)validate_password(默认内置)
审计日志需要第三方插件内置审计日志插件
权限回收支持支持,增加了更多选项

角色管理(MySQL 8.0+)

创建和使用角色

sql
-- 创建角色
CREATE ROLE 'app_role', 'readonly_role';

-- 授予角色权限
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_role';
GRANT SELECT ON app_db.* TO 'readonly_role';

-- 为用户分配角色
GRANT 'app_role' TO 'app_user'@'192.168.1.%';
GRANT 'readonly_role' TO 'readonly_user'@'%';

-- 激活角色
SET DEFAULT ROLE ALL TO 'app_user'@'192.168.1.%';
SET DEFAULT ROLE ALL TO 'readonly_user'@'%';

常见问题(FAQ)

Q1: 如何确保MySQL访问控制的安全性?

A1: 确保MySQL访问控制安全性的方法:

  • 实施最小权限原则
  • 使用强密码策略
  • 限制远程访问
  • 定期审查用户权限
  • 启用审计日志
  • 删除不必要的用户和数据库
  • 启用SSL/TLS加密

Q2: 如何备份和恢复MySQL用户权限?

A2: 备份和恢复MySQL用户权限的方法:

  • 备份mysql数据库:mysqldump -u root -p mysql > mysql_grants_backup.sql
  • 恢复mysql数据库:mysql -u root -p mysql < mysql_grants_backup.sql
  • 使用SHOW GRANTS语句备份单个用户权限

Q3: 如何处理MySQL用户密码忘记的情况?

A3: 处理MySQL用户密码忘记的情况:

  • 使用root用户重置密码:ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';
  • 如果root密码忘记,需要以跳过授权表的方式启动MySQL,然后重置密码

Q4: 如何限制用户只能访问特定的IP地址?

A4: 限制用户只能访问特定IP地址的方法:

  • 在创建用户时指定IP地址:CREATE USER 'username'@'192.168.1.100' IDENTIFIED BY 'password';
  • 使用通配符限制网段:CREATE USER 'username'@'192.168.1.%' IDENTIFIED BY 'password';

Q5: 如何审计MySQL用户活动?

A5: 审计MySQL用户活动的方法:

  • 启用MySQL审计日志
  • 使用第三方审计工具,如Percona Audit Log Plugin
  • 监控MySQL的general_log和slow_query_log
  • 使用Performance Schema监控用户活动

Q6: 如何实现MySQL的读写分离权限?

A6: 实现MySQL读写分离权限的方法:

  • 为主库用户授予读写权限:GRANT SELECT, INSERT, UPDATE, DELETE ON db.* TO 'write_user'@'host';
  • 为从库用户授予只读权限:GRANT SELECT ON db.* TO 'read_user'@'host';
  • 使用中间件(如MyCAT、ShardingSphere)实现自动读写分离

Q7: 如何安全地迁移MySQL用户权限?

A7: 安全迁移MySQL用户权限的方法:

  • 使用mysqldump备份mysql数据库
  • 在目标服务器上恢复mysql数据库
  • 刷新权限:FLUSH PRIVILEGES;
  • 验证用户权限是否正确

Q8: 如何防止MySQL暴力破解攻击?

A8: 防止MySQL暴力破解攻击的方法:

  • 使用强密码策略
  • 限制允许连接的IP地址
  • 启用fail2ban等工具监控和阻止暴力破解尝试
  • 调整max_connect_errors参数:SET GLOBAL max_connect_errors = 5;

Q9: 如何实现MySQL的多因素认证?

A9: 实现MySQL多因素认证的方法:

  • MySQL 8.0.27+支持双因素认证
  • 配置PAM认证插件
  • 结合外部认证系统,如LDAP、Active Directory

Q10: 如何定期审查MySQL用户权限?

A10: 定期审查MySQL用户权限的方法:

  • 制定权限审查计划(每月或每季度)
  • 使用脚本自动生成权限报告
  • 检查是否有不必要的权限
  • 检查是否有过期的用户
  • 检查是否有异常的用户活动