1. 首页 > MySQL教程 > 正文

MySQL教程FG188-MySQL服务器安全管理

内容简介:MySQL服务器安全管理是数据库运维的重要组成部分,对于保障数据安全和业务连续性至关重要。本文风哥教程参考MySQL官方文档Security部分,详细介绍MySQL服务器安全管理的各种策略、工具和最佳实践,包括认证与授权、密码策略、访问控制、加密、审计和安全配置等内容,帮助读者建立完善的MySQL安全防护体系。学习交流加群风哥微信:
itpux-com

Part01-基础概念与理论知识

1.1 MySQL安全概述

MySQL服务器安全管理是指保护MySQL数据库免受未经授权的访问、修改和破坏的过程。安全管理的主要目标包括:

  • 数据机密性:确保只有授权用户能够访问敏感数据
  • 数据完整性:确保数据不被未经授权的修改或破坏
  • 数据可用性:确保授权用户能够及时访问所需的数据
  • 合规性:满足行业或法规对数据安全的要求

1.2 常见安全威胁

MySQL服务器面临的常见安全威胁包括:

  • 未授权访问:未经授权的用户尝试访问数据库
  • 弱密码:用户使用容易猜测的密码
  • SQL注入:攻击者通过输入恶意SQL语句来操纵数据库
  • 权限滥用:授权用户超越其权限访问或修改数据
  • 数据泄露:敏感数据被泄露给未经授权的第三方
  • 拒绝服务攻击:攻击者尝试使数据库服务不可用
  • 恶意软件:通过恶意软件感染数据库服务器
  • 配置错误:安全配置不当导致的安全漏洞

1.3 安全设计原则

MySQL服务器安全设计应遵循以下原则:

  • 最小权限原则:只授予用户完成其工作所需的最小权限
  • 纵深防御原则:采用多层安全措施,即使一层被突破,还有其他层保护
  • 安全默认配置:使用安全的默认配置,避免不必要的风险
  • 定期更新和补丁:及时更新MySQL版本和应用安全补丁
  • 监控和审计:持续监控数据库活动,定期审计安全配置
  • 备份和恢复:定期备份数据,确保在安全事件发生时能够快速恢复
  • 安全培训:对数据库管理员和用户进行安全培训,提高安全意识
安全设计建议:在设计MySQL安全体系时,应综合考虑技术、流程和人员等因素,建立全面的安全防护体系。

Part02-生产环境规划与建议

2.1 安全策略规划

在生产环境中,MySQL安全策略的规划需要考虑以下因素:

  • 业务需求:了解业务对数据安全的要求,如数据敏感性、合规要求等
  • 风险评估:评估数据库面临的安全风险,确定安全优先级
  • 安全目标:制定明确的安全目标,如数据机密性、完整性和可用性
  • 安全措施:选择合适的安全措施,如认证、授权、加密、审计等
  • 安全流程:建立安全管理流程,如用户管理、权限管理、审计流程等
  • 应急响应:制定安全事件应急响应流程,确保在安全事件发生时能够快速响应

2.2 安全需求分析

在设计安全策略之前,需要进行安全需求分析,包括:

  • 数据分类:对数据进行分类,确定哪些数据需要特殊保护
  • 访问控制需求:确定不同用户对不同数据的访问权限
  • 加密需求:确定哪些数据需要加密,以及加密的方式
  • 审计需求:确定需要审计的数据库活动,以及审计数据的保留时间
  • 合规需求:确定需要满足的行业或法规要求,如GDPR、PCI DSS等
  • 性能需求:确保安全措施不会对数据库性能造成过大影响

2.3 安全架构设计

根据安全需求分析,设计合适的安全架构:

  • 网络架构:采用网络隔离、防火墙、VPN等措施,保护数据库服务器
  • 系统架构:采用最小化安装、定期更新、安全配置等措施,保护操作系统
  • 数据库架构:采用安全配置、访问控制、加密、审计等措施,保护数据库
  • 应用架构:采用参数化查询、输入验证等措施,防止SQL注入等攻击
  • 备份架构:采用加密备份、异地存储等措施,保护备份数据
  • 监控架构:采用安全监控、入侵检测等措施,及时发现安全事件
风哥提示:安全策略的规划需要与业务需求相匹配,确保在保障安全的同时,不影响业务的正常运行。同时,安全策略需要定期更新和优化,以适应新的安全威胁和业务需求的变化。

Part03-生产环境项目实施方案

3.1 认证与授权管理

认证与授权是MySQL安全管理的基础,用于验证用户身份和控制用户访问权限。

3.1.1 用户管理

# 1. 创建用户
mysql> CREATE USER ‘app_user’@’localhost’ IDENTIFIED BY ‘strong_password’;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER ‘app_user’@’192.168.1.%’ IDENTIFIED BY ‘strong_password’;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER ‘read_user’@’%’ IDENTIFIED BY ‘read_only_password’;
Query OK, 0 rows affected (0.00 sec)

# 2. 查看用户
mysql> SELECT user, host FROM mysql.user;
+——————+————-+
| user | host |
+——————+————-+
| app_user | 192.168.1.% |
| app_user | localhost |
| read_user | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+——————+————-+

# 3. 修改用户密码
mysql> ALTER USER ‘app_user’@’localhost’ IDENTIFIED BY ‘new_strong_password’;
Query OK, 0 rows affected (0.00 sec)

# 4. 删除用户
mysql> DROP USER ‘read_user’@’%’;
Query OK, 0 rows affected (0.00 sec)

# 5. 锁定和解锁用户
mysql> ALTER USER ‘app_user’@’localhost’ ACCOUNT LOCK;
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER USER ‘app_user’@’localhost’ ACCOUNT UNLOCK;
Query OK, 0 rows affected (0.00 sec)

# 6. 查看用户状态
mysql> SELECT user, host, account_locked FROM mysql.user;
+——————+————-+—————-+———-+
| user | host | account_locked | … |
+——————+————-+—————-+———-+
| app_user | 192.168.1.% | N | … |
| app_user | localhost | N | … |
| mysql.infoschema | localhost | Y | … |
| mysql.session | localhost | Y | … |
| mysql.sys | localhost | Y | … |
| root | localhost | N | … |
+——————+————-+—————-+———-+

3.1.2 权限管理

# 1. 授予权限
# 授予用户对特定数据库的所有权限
mysql> GRANT ALL PRIVILEGES ON fgedudb.* TO ‘app_user’@’localhost’;
Query OK, 0 rows affected (0.00 sec)

# 授予用户对特定表的SELECT和INSERT权限
mysql> GRANT SELECT, INSERT ON fgedudb.table1 TO ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.00 sec)

# 授予用户只读权限
mysql> GRANT SELECT ON *.* TO ‘read_user’@’%’ WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

# 2. 查看权限
mysql> SHOW GRANTS FOR ‘app_user’@’localhost’;
+———————————————————-+
| Grants for app_user@localhost |
+———————————————————-+
| GRANT USAGE ON *.* TO `app_user`@`localhost` |
| GRANT ALL PRIVILEGES ON `fgedudb`.* TO `app_user`@`localhost` |
+———————————————————-+

mysql> SHOW GRANTS FOR ‘app_user’@’192.168.1.%’;
+—————————————————————+
| Grants for app_user@192.168.1.% |
+—————————————————————+
| GRANT USAGE ON *.* TO `app_user`@`192.168.1.%` |
| GRANT SELECT, INSERT ON `fgedudb`.`table1` TO `app_user`@`192.168.1.%` |
+—————————————————————+

# 3. 撤销权限
mysql> REVOKE INSERT ON fgedudb.table1 FROM ‘app_user’@’192.168.1.%’;
Query OK, 0 rows affected (0.00 sec)

# 4. 刷新权限
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

# 5. 查看当前用户权限
mysql> SHOW GRANTS;
+———————————————————-+
| Grants for app_user@localhost |
+———————————————————-+
| GRANT USAGE ON *.* TO `app_user`@`localhost` |
| GRANT ALL PRIVILEGES ON `fgedudb`.* TO `app_user`@`localhost` |
+———————————————————-+

3.2 密码策略

密码策略用于确保用户使用强密码,减少密码被猜测或破解的风险。

# 1. 查看密码策略配置
mysql> SHOW GLOBAL VARIABLES LIKE ‘validate_password%’;
+————————————–+——–+
| Variable_name | Value |
+————————————–+——–+
| validate_password.check_user_name | ON |
| validate_password.dictionary_file | |
| validate_password.length | 8 |
| validate_password.mixed_case_count | 1 |
| validate_password.number_count | 1 |
| validate_password.policy | MEDIUM |
| validate_password.special_char_count | 1 |
+————————————–+——–+

# 2. 修改密码策略
# 设置密码长度为12
mysql> SET GLOBAL validate_password.length = 12;
Query OK, 0 rows affected (0.00 sec)

# 设置密码策略为STRONG
mysql> SET GLOBAL validate_password.policy = ‘STRONG’;
Query OK, 0 rows affected (0.00 sec)

# 设置至少需要2个数字
mysql> SET GLOBAL validate_password.number_count = 2;
Query OK, 0 rows affected (0.00 sec)

# 设置至少需要2个特殊字符
mysql> SET GLOBAL validate_password.special_char_count = 2;
Query OK, 0 rows affected (0.00 sec)

# 3. 验证密码策略
# 尝试创建弱密码用户(应该失败)
mysql> CREATE USER ‘weak_user’@’localhost’ IDENTIFIED BY ‘password’;
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

# 创建符合策略的强密码用户
mysql> CREATE USER ‘strong_user’@’localhost’ IDENTIFIED BY ‘MyS3cr3tP@ssw0rd’;
Query OK, 0 rows affected (0.00 sec)

# 4. 设置密码过期策略
# 设置密码30天后过期
mysql> ALTER USER ‘app_user’@’localhost’ PASSWORD EXPIRE INTERVAL 30 DAY;
Query OK, 0 rows affected (0.00 sec)

# 设置密码永不过期
mysql> ALTER USER ‘read_user’@’%’ PASSWORD EXPIRE NEVER;
Query OK, 0 rows affected (0.00 sec)

# 5. 强制用户下次登录时修改密码
mysql> ALTER USER ‘new_user’@’localhost’ PASSWORD EXPIRE DEFAULT;
Query OK, 0 rows affected (0.00 sec)

# 6. 查看用户密码过期信息
mysql> SELECT user, host, password_expired, password_lifetime FROM mysql.user;
+——————+————-+——————+——————-+
| user | host | password_expired | password_lifetime |
+——————+————-+——————+——————-+
| app_user | 192.168.1.% | N | NULL |
| app_user | localhost | N | 30 |
| read_user | % | N | NULL |
| new_user | localhost | Y | NULL |
| mysql.infoschema | localhost | N | NULL |
| mysql.session | localhost | N | NULL |
| mysql.sys | localhost | N | NULL |
| root | localhost | N | NULL |
+——————+————-+——————+——————-+

3.3 访问控制

访问控制用于限制用户对数据库的访问,包括网络访问控制和资源访问控制。

# 1. 网络访问控制
# 配置MySQL只监听特定IP地址
# vi /etc/my.cnf
bind-address = 127.0.0.1,192.168.1.100

# 重启MySQL服务
# systemctl restart mysqld

# 验证监听地址
# netstat -tlnp | grep mysql
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1234/mysqld
tcp 0 0 192.168.1.100:3306 0.0.0.0:* LISTEN 1234/mysqld

# 2. 用户主机限制
# 创建只能从特定IP访问的用户
mysql> CREATE USER ‘app_user’@’192.168.1.100’ IDENTIFIED BY ‘strong_password’;
Query OK, 0 rows affected (0.00 sec)

# 创建只能从本地访问的用户
mysql> CREATE USER ‘local_user’@’localhost’ IDENTIFIED BY ‘local_password’;
Query OK, 0 rows affected (0.00 sec)

# 3. 资源访问控制
# 设置用户最大连接数
mysql> CREATE USER ‘limited_user’@’localhost’ IDENTIFIED BY ‘limited_password’ WITH MAX_USER_CONNECTIONS 10;
Query OK, 0 rows affected (0.00 sec)

# 设置用户每小时最大查询数
mysql> CREATE USER ‘query_user’@’localhost’ IDENTIFIED BY ‘query_password’ WITH MAX_QUERIES_PER_HOUR 1000;
Query OK, 0 rows affected (0.00 sec)

# 设置用户每小时最大更新数
mysql> CREATE USER ‘update_user’@’localhost’ IDENTIFIED BY ‘update_password’ WITH MAX_UPDATES_PER_HOUR 500;
Query OK, 0 rows affected (0.00 sec)

# 4. 查看用户资源限制
mysql> SELECT user, host, max_connections, max_queries_per_hour, max_updates_per_hour FROM mysql.user;
+——————+————-+—————–+———————–+———————–+
| user | host | max_connections | max_queries_per_hour | max_updates_per_hour |
+——————+————-+—————–+———————–+———————–+
| app_user | 192.168.1.% | 0 | 0 | 0 |
| limited_user | localhost | 10 | 0 | 0 |
| query_user | localhost | 0 | 1000 | 0 |
| update_user | localhost | 0 | 0 | 500 |
| mysql.infoschema | localhost | 0 | 0 | 0 |
| mysql.session | localhost | 0 | 0 | 0 |
| mysql.sys | localhost | 0 | 0 | 0 |
| root | localhost | 0 | 0 | 0 |
+——————+————-+—————–+———————–+———————–+

3.4 加密设置

加密用于保护数据的机密性,包括传输加密和静态加密。

3.4.1 SSL/TLS传输加密

# 1. 生成SSL证书
# 创建证书目录
$ mkdir -p /mysql/ssl
$ cd /mysql/ssl

# 生成CA证书
$ openssl genrsa 2048 > ca-key.pem
$ openssl req -new -x509 -nodes -days 3650 -key ca-key.pem > ca.pem

# 生成服务器证书
$ openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem
$ openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 >
server-cert.pem

# 生成客户端证书
$ openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem > client-req.pem
$ openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 >
client-cert.pem

# 修改证书权限
$ chown -R mysql:mysql /mysql/ssl
$ chmod 600 /mysql/ssl/*-key.pem
$ chmod 644 /mysql/ssl/*.pem

# 2. 配置MySQL启用SSL
# vi /etc/my.cnf
[mysqld]
ssl-ca=/mysql/ssl/ca.pem
ssl-cert=/mysql/ssl/server-cert.pem
ssl-key=/mysql/ssl/server-key.pem

# 重启MySQL服务
# systemctl restart mysqld

# 3. 验证SSL配置
mysql> SHOW GLOBAL VARIABLES LIKE ‘%ssl%’;
+———————+——————————–+——–+
| Variable_name | Value | … |
+———————+——————————–+——–+
| have_openssl | YES | … |
| have_ssl | YES | … |
| ssl_ca | /mysql/ssl/ca.pem | … |
| ssl_capath | | … |
| ssl_cert | /mysql/ssl/server-cert.pem | … |
| ssl_cipher | | … |
| ssl_crl | | … |
| ssl_crlpath | | … |
| ssl_key | /mysql/ssl/server-key.pem | … |
| version_ssl_library | OpenSSL 1.1.1k FIPS 25 Mar 2021 | … |
+———————+——————————–+——–+

# 4. 创建需要SSL的用户
mysql> CREATE USER ‘ssl_user’@’localhost’ IDENTIFIED BY ‘ssl_password’ REQUIRE SSL;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER ‘x509_user’@’localhost’ IDENTIFIED BY ‘x509_password’ REQUIRE X509;
Query OK, 0 rows affected (0.00 sec)

# 5. 使用SSL连接MySQL
$ mysql -u ssl_user -p –ssl-ca=/mysql/ssl/ca.pem –ssl-cert=/mysql/ssl/client-cert.pem
–ssl-key=/mysql/ssl/client-key.pem
Enter password:

mysql> STATUS;
————–
mysql Ver 8.0.32 for Linux on x86_64 (MySQL Community Server – GPL)

Connection id: 123
Current database:
Current user: ssl_user@localhost
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
Current pager: stdout
Using outfile: ”
Using delimiter: ;
Server version: 8.0.32 MySQL Community Server – GPL
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /var/lib/mysql/mysql.sock
Binary data as: Hexadecimal
Uptime: 1 hour 30 min 45 sec

Threads: 10 Questions: 1000 Slow queries: 0 Opens: 200 Flush tables: 1 Open tables: 150 Queries per second
avg: 0.184
————–

3.4.2 数据静态加密

# 1. 查看InnoDB加密配置
mysql> SHOW GLOBAL VARIABLES LIKE ‘innodb_encrypt%’;
+———————————-+——-+
| Variable_name | Value |
+———————————-+——-+
| innodb_encrypt_log | OFF |
| innodb_encrypt_tables | OFF |
| innodb_encryption_rotate_key_age | 1 |
| innodb_encryption_rotation_iops | 100 |
| innodb_encryption_threads | 4 |
| innodb_encrypt_temporary_tables | OFF |
+———————————-+——-+

# 2. 启用表空间加密
# 设置加密密钥管理插件
# vi /etc/my.cnf
[mysqld]
early-plugin-load=file_key_management.so
file_key_management_filename=/mysql/keys/keyfile.enc
file_key_management_filekey=”FILE:/mysql/keys/keyfile.passwd”
file_key_management_encryption_algorithm=aes_ctr
innodb_encrypt_tables=ON
innodb_encrypt_log=ON

# 创建密钥文件
$ mkdir -p /mysql/keys
$ openssl rand -hex 32 > /mysql/keys/keyfile.enc
$ chown -R mysql:mysql /mysql/keys
$ chmod 600 /mysql/keys/*

# 创建密码文件
$ echo “mysecretpassword” > /mysql/keys/keyfile.passwd
$ chown mysql:mysql /mysql/keys/keyfile.passwd
$ chmod 400 /mysql/keys/keyfile.passwd

# 重启MySQL服务
# systemctl restart mysqld

# 3. 创建加密表
mysql> CREATE TABLE encrypted_table (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
sensitive_data VARCHAR(255)
) ENGINE=InnoDB ENCRYPTION=’Y’;
Query OK, 0 rows affected (0.00 sec)

# 4. 查看表加密状态
mysql> SELECT NAME, SPACE, ENCRYPTION FROM information_schema.INNODB_TABLESPACES WHERE NAME LIKE
‘%encrypted_table%’;
+—————————+——-+————+
| NAME | SPACE | ENCRYPTION |
+—————————+——-+————+
| fgedudb/encrypted_table | 12 | YES |
+—————————+——-+————+

# 5. 列级加密
mysql> CREATE TABLE credit_cards (
id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT,
card_number VARBINARY(255),
expiration_date VARBINARY(255)
);
Query OK, 0 rows affected (0.00 sec)

# 插入加密数据
mysql> INSERT INTO credit_cards (customer_id, card_number, expiration_date)
VALUES (1, AES_ENCRYPT(‘1234-5678-9012-3456’, ‘encryption_key’),
AES_ENCRYPT(’12/28′, ‘encryption_key’));
Query OK, 1 row affected (0.00 sec)

# 查询解密数据
mysql> SELECT customer_id,
CAST(AES_DECRYPT(card_number, ‘encryption_key’) AS CHAR) AS card_number,
CAST(AES_DECRYPT(expiration_date, ‘encryption_key’) AS CHAR) AS expiration_date
FROM credit_cards;
+————-+———————-+——————+
| customer_id | card_number | expiration_date |
+————-+———————-+——————+
| 1 | 1234-5678-9012-3456 | 12/28 |
+————-+———————-+——————+

3.5 审计配置

审计用于记录数据库活动,便于监控和排查安全事件。

# 1. 安装审计插件
mysql> INSTALL PLUGIN audit_log SONAME ‘audit_log.so’;
Query OK, 0 rows affected (0.00 sec)

# 2. 配置审计日志
# vi /etc/my.cnf
[mysqld]
plugin-load=audit_log.so
audit_log_policy=ALL
# audit_log_policy=LOGINS # 只记录登录事件
# audit_log_policy=QUERIES # 只记录查询事件
# audit_log_policy=NONE # 不记录任何事件

audit_log_file=/mysql/logs/audit.log
audit_log_format=JSON
audit_log_rotate_on_size=104857600 # 100MB

# 3. 查看审计配置
mysql> SHOW GLOBAL VARIABLES LIKE ‘audit_log%’;
+—————————–+——————————-+
| Variable_name | Value |
+—————————–+——————————-+
| audit_log_buffer_size | 1048576 |
| audit_log_connection_policy | ALL |
| audit_log_current_session | ON |
| audit_log_database_engine | OFF |
| audit_log_exclude_accounts | |
| audit_log_file | /mysql/logs/audit.log |
| audit_log_flush | OFF |
| audit_log_format | JSON |
| audit_log_include_accounts | |
| audit_log_policy | ALL |
| audit_log_rotate_on_size | 104857600 |
| audit_log_rotations | 0 |
| audit_log_strategy | ASYNCHRONOUS |
+—————————–+——————————-+

# 4. 查看审计日志
# tail -n 10 /mysql/logs/audit.log
{“audit_record”:{“name”:”Connect”,”recorded_time”:”2026-04-07T22:00:00″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”root”,”priv_user”:”root”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:””}}
{“audit_record”:{“name”:”Query”,”recorded_time”:”2026-04-07T22:00:10″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”root”,”priv_user”:”root”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:”fgedudb”,”sql_text”:”SELECT
* FROM table1 WHERE id = 1″}}
{“audit_record”:{“name”:”Query”,”recorded_time”:”2026-04-07T22:00:20″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”root”,”priv_user”:”root”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:”fgedudb”,”sql_text”:”UPDATE
table1 SET name = ‘updated’ WHERE id = 1″}}
{“audit_record”:{“name”:”Disconnect”,”recorded_time”:”2026-04-07T22:00:30″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”root”,”priv_user”:”root”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:”fgedudb”}}

# 5. 使用Performance Schema进行审计
# 启用Performance Schema
mysql> SET GLOBAL performance_schema = ON;
Query OK, 0 rows affected (0.00 sec)

# 查看连接审计
mysql> SELECT * FROM performance_schema.host_cache;
+———–+————+—————-+———————+——————-+
| IP | HOST | HOST_VALIDATED | SUM_CONNECT_ERRORS | COUNT_HOST_BLOCKED |
+———–+————+—————-+———————+——————-+
| 127.0.0.1 | localhost | YES | 0 | 0 |
| 192.168.1.100 | host100 | YES | 0 | 0 |
| 192.168.1.200 | host200 | YES | 10 | 1 |
+———–+————+—————-+———————+——————-+

# 查看查询审计
mysql> SELECT * FROM performance_schema.events_statements_history WHERE sql_text LIKE ‘%DELETE%’ LIMIT 10;
+———————+———————+————+———–+———–+
| THREAD_ID | EVENT_ID | SQL_TEXT | TIMER_WAIT| RETURNED_SQLSTATE |
+———————+———————+————+———–+———–+
| 123 | 456 | DELETE FROM table1 WHERE id = 1 | 1000000000 | 00000 |
+———————+———————+————+———–+———–+

3.6 安全配置

安全配置用于优化MySQL的安全设置,减少安全漏洞。

# 1. 禁用不必要的插件
mysql> SHOW PLUGINS;
+—————————-+———-+——————–+———————-+——–+
| Name | Status | Type | Library | License |
+—————————-+———-+——————–+———————-+——–+
| binlog | ACTIVE | STORAGE ENGINE | NULL | GPL |
| mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| sha256_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| caching_sha2_password | ACTIVE | AUTHENTICATION | NULL | GPL |
| sha2_cache_cleaner | ACTIVE | AUDIT | NULL | GPL |
| innodb | ACTIVE | STORAGE ENGINE | NULL | GPL |
| INNODB_TRX | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
| INNODB_LOCKS | ACTIVE | INFORMATION SCHEMA | NULL | GPL |
| … | … | … | … | … |
+—————————-+———-+——————–+———————-+——–+

# 禁用不必要的插件
mysql> UNINSTALL PLUGIN example_plugin;
Query OK, 0 rows affected (0.00 sec)

# 2. 限制系统变量修改权限
# 防止普通用户修改系统变量
# vi /etc/my.cnf
[mysqld]
# 只允许SUPER权限用户修改的变量
secure_file_priv=/mysql/tmp

# 3. 启用严格SQL模式
# vi /etc/my.cnf
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

# 4. 禁用本地文件访问
# vi /etc/my.cnf
[mysqld]
secure_file_priv=”” # 禁用LOAD_FILE()函数

# 5. 限制连接超时
# vi /etc/my.cnf
[mysqld]
wait_timeout=7200
interactive_timeout=7200
connect_timeout=10

# 6. 启用密码验证插件
# vi /etc/my.cnf
[mysqld]
plugin-load-add=validate_password.so
validate_password_policy=STRONG
validate_password_length=12

# 7. 禁用符号链接
# vi /etc/my.cnf
[mysqld]
skip-symbolic-links

# 8. 重启MySQL服务使配置生效
# systemctl restart mysqld

# 9. 运行安全加固脚本
# 使用mysql_secure_installation脚本加固MySQL
$ mysql_secure_installation

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: y

There are three levels of password validation policy:

LOW Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2

Please set the password for root here.

New password:

Re-enter new password:

Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have

a user account created for them. This is intended only for

testing, and to make the installation go a bit smoother.

You should remove them before moving into a production

environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y

Success.

Normally, root should only be allowed to connect from

‘localhost’. This ensures that someone cannot guess at

the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y

Success.

By default, MySQL comes with a database named ‘test’ that

anyone can access. This is also intended only for testing,

and should be removed before moving into a production

environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y

– Dropping test database…

Success.

– Removing privileges on test database…

Success.

Reloading the privilege tables will ensure that all changes

made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y

Success.

All done!

Part04-生产案例与实战讲解

4.1 用户权限管理实战

用户权限管理的实战案例。

案例:电商系统数据库用户权限管理
系统需求:
– 应用程序需要对订单表进行读写操作
– 数据分析团队需要对订单表进行只读查询
– DBA需要对所有数据库进行管理操作
– 限制用户只能从特定IP访问

# 1. 创建用户
# 创建应用程序用户(只能从应用服务器访问)
mysql> CREATE USER ‘ecommerce_app’@’192.168.1.100’ IDENTIFIED BY ‘App_Secret_Pass123!’;
Query OK, 0 rows affected (0.00 sec)

# 创建数据分析用户(只能从数据分析服务器访问)
mysql> CREATE USER ‘data_analyst’@’192.168.1.200’ IDENTIFIED BY ‘Analyst_Secret_Pass456!’;
Query OK, 0 rows affected (0.00 sec)

# 创建DBA用户(只能从管理服务器访问)
mysql> CREATE USER ‘dba_admin’@’192.168.1.300’ IDENTIFIED BY ‘DBA_Secret_Pass789!’;
Query OK, 0 rows affected (0.00 sec)

# 2. 授予权限
# 授予应用程序用户对订单数据库的读写权限
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON ecommerce_db.orders TO ‘ecommerce_app’@’192.168.1.100’;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON ecommerce_db.order_items TO ‘ecommerce_app’@’192.168.1.100’;
mysql> GRANT SELECT ON ecommerce_db.products TO ‘ecommerce_app’@’192.168.1.100’;
mysql> GRANT SELECT ON ecommerce_db.customers TO ‘ecommerce_app’@’192.168.1.100’;

# 授予数据分析用户对订单数据库的只读权限
mysql> GRANT SELECT ON ecommerce_db.orders TO ‘data_analyst’@’192.168.1.200’;
mysql> GRANT SELECT ON ecommerce_db.order_items TO ‘data_analyst’@’192.168.1.200’;
mysql> GRANT SELECT ON ecommerce_db.products TO ‘data_analyst’@’192.168.1.200’;
mysql> GRANT SELECT ON ecommerce_db.customers TO ‘data_analyst’@’192.168.1.200’;

# 授予DBA用户所有权限
mysql> GRANT ALL PRIVILEGES ON *.* TO ‘dba_admin’@’192.168.1.300’ WITH GRANT OPTION;

# 3. 验证权限
# 应用程序用户权限
mysql> SHOW GRANTS FOR ‘ecommerce_app’@’192.168.1.100’;
+————————————————————————–+
| Grants for ecommerce_app@192.168.1.100 |
+————————————————————————–+
| GRANT USAGE ON *.* TO `ecommerce_app`@`192.168.1.100` |
| GRANT SELECT ON `ecommerce_db`.`products` TO `ecommerce_app`@`192.168.1.100` |
| GRANT SELECT ON `ecommerce_db`.`customers` TO `ecommerce_app`@`192.168.1.100` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `ecommerce_db`.`orders` TO `ecommerce_app`@`192.168.1.100` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `ecommerce_db`.`order_items` TO `ecommerce_app`@`192.168.1.100` |
+————————————————————————–+

# 数据分析用户权限
mysql> SHOW GRANTS FOR ‘data_analyst’@’192.168.1.200’;
+—————————————————————————+
| Grants for data_analyst@192.168.1.200 |
+—————————————————————————+
| GRANT USAGE ON *.* TO `data_analyst`@`192.168.1.200` |
| GRANT SELECT ON `ecommerce_db`.`products` TO `data_analyst`@`192.168.1.200` |
| GRANT SELECT ON `ecommerce_db`.`customers` TO `data_analyst`@`192.168.1.200` |
| GRANT SELECT ON `ecommerce_db`.`orders` TO `data_analyst`@`192.168.1.200` |
| GRANT SELECT ON `ecommerce_db`.`order_items` TO `data_analyst`@`192.168.1.200` |
+—————————————————————————+

# DBA用户权限
mysql> SHOW GRANTS FOR ‘dba_admin’@’192.168.1.300’;
+——————————————————————+
| Grants for dba_admin@192.168.1.300 |
+——————————————————————+
| GRANT ALL PRIVILEGES ON *.* TO `dba_admin`@`192.168.1.300` WITH GRANT OPTION |
+——————————————————————+

# 4. 测试用户访问
# 从应用服务器测试应用程序用户访问
# ssh 192.168.1.100
$ mysql -u ecommerce_app -p -h 192.168.1.10
Enter password:

mysql> USE ecommerce_db;
Database changed

mysql> INSERT INTO orders (customer_id, order_date, total_amount) VALUES (1, ‘2026-04-07’, 100.00);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM orders WHERE id = LAST_INSERT_ID();
+—-+————-+————+————–+
| id | customer_id | order_date | total_amount |
+—-+————-+————+————–+
| 101 | 1 | 2026-04-07 | 100.00 |
+—-+————-+————+————–+

mysql> DROP TABLE orders;
ERROR 1142 (42000): DROP command denied to user ‘ecommerce_app’@’192.168.1.100’ for table ‘orders’

# 从数据分析服务器测试数据分析用户访问
# ssh 192.168.1.200
$ mysql -u data_analyst -p -h 192.168.1.10
Enter password:

mysql> USE ecommerce_db;
Database changed

mysql> SELECT COUNT(*) FROM orders;
+———-+
| COUNT(*) |
+———-+
| 101 |
+———-+

mysql> INSERT INTO orders (customer_id, order_date, total_amount) VALUES (2, ‘2026-04-07’, 200.00);
ERROR 1142 (42000): INSERT command denied to user ‘data_analyst’@’192.168.1.200’ for table ‘orders’

4.2 数据加密实战

数据加密的实战案例。

案例:金融系统敏感数据加密
系统需求:
– 对用户的银行卡信息进行加密存储
– 对用户的身份证号码进行加密存储
– 确保数据在传输过程中加密

# 1. 配置SSL/TLS传输加密
# 生成SSL证书(参考3.4.1部分)

# 配置MySQL启用SSL
# vi /etc/my.cnf
[mysqld]
ssl-ca=/mysql/ssl/ca.pem
ssl-cert=/mysql/ssl/server-cert.pem
ssl-key=/mysql/ssl/server-key.pem

# 重启MySQL服务
# systemctl restart mysqld

# 2. 创建需要SSL的用户
mysql> CREATE USER ‘finance_app’@’192.168.1.100’ IDENTIFIED BY ‘Finance_Secret_Pass123!’ REQUIRE SSL;
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON finance_db.* TO ‘finance_app’@’192.168.1.100’;
Query OK, 0 rows affected (0.00 sec)

# 3. 创建加密表
mysql> CREATE TABLE user_bank_cards (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
card_number VARBINARY(255) NOT NULL, # 加密存储银行卡号
card_type VARCHAR(50) NOT NULL,
expiration_date VARBINARY(255) NOT NULL, # 加密存储有效期
cvv VARBINARY(255) NOT NULL, # 加密存储CVV
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE user_identities (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
id_card_number VARBINARY(255) NOT NULL, # 加密存储身份证号码
name VARCHAR(100) NOT NULL,
gender VARCHAR(10) NOT NULL,
birth_date DATE NOT NULL,
address VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)

# 4. 插入加密数据
# 使用应用程序加密密钥
$ ENCRYPTION_KEY=”Financial_Security_Key_2026″

# 插入银行卡数据
mysql> INSERT INTO user_bank_cards (user_id, card_number, card_type, expiration_date, cvv)
VALUES (1,
AES_ENCRYPT(‘6222021234567890123’, ‘$ENCRYPTION_KEY’),
‘Debit Card’,
AES_ENCRYPT(’12/28′, ‘$ENCRYPTION_KEY’),
AES_ENCRYPT(‘123’, ‘$ENCRYPTION_KEY’));
Query OK, 1 row affected (0.00 sec)

# 插入身份证数据
mysql> INSERT INTO user_identities (user_id, id_card_number, name, gender, birth_date, address)
VALUES (1,
AES_ENCRYPT(‘110101199001011234’, ‘$ENCRYPTION_KEY’),
‘张三’,
‘男’,
‘1990-01-01’,
‘北京市朝阳区’);
Query OK, 1 row affected (0.00 sec)

# 5. 查询解密数据
mysql> SELECT user_id,
CAST(AES_DECRYPT(card_number, ‘$ENCRYPTION_KEY’) AS CHAR) AS card_number,
card_type,
CAST(AES_DECRYPT(expiration_date, ‘$ENCRYPTION_KEY’) AS CHAR) AS expiration_date,
CAST(AES_DECRYPT(cvv, ‘$ENCRYPTION_KEY’) AS CHAR) AS cvv
FROM user_bank_cards WHERE user_id = 1;
+———+———————-+————+——————+——+
| user_id | card_number | card_type | expiration_date | cvv |
+———+———————-+————+——————+——+
| 1 | 6222021234567890123 | Debit Card | 12/28 | 123 |
+———+———————-+————+——————+——+

mysql> SELECT user_id,
CAST(AES_DECRYPT(id_card_number, ‘$ENCRYPTION_KEY’) AS CHAR) AS id_card_number,
name, gender, birth_date, address
FROM user_identities WHERE user_id = 1;
+———+——————+——–+——–+————+——————+
| user_id | id_card_number | name | gender | birth_date | address |
+———+——————+——–+——–+————+——————+
| 1 | 110101199001011234 | 张三 | 男 | 1990-01-01 | 北京市朝阳区 |
+———+——————+——–+——–+————+——————+

# 6. 验证SSL连接
# 从应用服务器连接MySQL
# ssh 192.168.1.100
$ mysql -u finance_app -p –ssl-ca=/mysql/ssl/ca.pem –ssl-cert=/mysql/ssl/client-cert.pem
–ssl-key=/mysql/ssl/client-key.pem -h 192.168.1.10
Enter password:

mysql> STATUS;
————–
mysql Ver 8.0.32 for Linux on x86_64 (MySQL Community Server – GPL)

Connection id: 123
Current database:
Current user: finance_app@192.168.1.100
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
Current pager: stdout
Using outfile: ”
Using delimiter: ;
Server version: 8.0.32 MySQL Community Server – GPL
Protocol version: 10
Connection: 192.168.1.10 via TCP/IP
TCP port: 3306
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
TCP port: 3306
Uptime: 2 hours 15 min 30 sec

Threads: 15 Questions: 2000 Slow queries: 0 Opens: 300 Flush tables: 1 Open tables: 200 Queries per second
avg: 0.256
————–

4.3 安全审计实战

安全审计的实战案例。

案例:数据库操作审计
系统需求:
– 审计所有用户的登录和登出事件
– 审计所有对敏感表的修改操作
– 审计所有权限变更操作
– 审计日志保留30天

# 1. 安装并配置审计插件
# 安装审计插件
mysql> INSTALL PLUGIN audit_log SONAME ‘audit_log.so’;
Query OK, 0 rows affected (0.00 sec)

# 配置审计日志
# vi /etc/my.cnf
[mysqld]
plugin-load=audit_log.so
audit_log_policy=ALL
audit_log_file=/mysql/logs/audit.log
audit_log_format=JSON
audit_log_rotate_on_size=104857600 # 100MB
audit_log_rotations=30 # 保留30个日志文件

# 重启MySQL服务
# systemctl restart mysqld

# 2. 配置Performance Schema进行细粒度审计
# 启用Performance Schema
mysql> SET GLOBAL performance_schema = ON;
Query OK, 0 rows affected (0.00 sec)

# 启用语句审计
mysql> UPDATE performance_schema.setup_instruments SET ENABLED = ‘YES’ WHERE NAME LIKE ‘statement/%’;
Query OK, 100 rows affected (0.00 sec)

mysql> UPDATE performance_schema.setup_consumers SET ENABLED = ‘YES’ WHERE NAME LIKE ‘%events_statements%’;
Query OK, 5 rows affected (0.00 sec)

# 3. 测试审计功能
# 测试登录事件
$ mysql -u app_user -p
Enter password:

mysql> USE fgedudb;
Database changed

mysql> UPDATE sensitive_table SET column1 = ‘value1’ WHERE id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> GRANT SELECT ON fgedudb.* TO ‘new_user’@’localhost’ IDENTIFIED BY ‘new_password’;
Query OK, 0 rows affected (0.00 sec)

mysql> exit;
Bye

# 4. 查看审计日志
# 查看登录事件
$ grep -i “Connect” /mysql/logs/audit.log | tail -n 5
{“audit_record”:{“name”:”Connect”,”recorded_time”:”2026-04-07T23:00:00″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”app_user”,”priv_user”:”app_user”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:””}}

# 查看修改操作
$ grep -i “UPDATE” /mysql/logs/audit.log | tail -n 5
{“audit_record”:{“name”:”Query”,”recorded_time”:”2026-04-07T23:00:10″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”app_user”,”priv_user”:”app_user”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:”fgedudb”,”sql_text”:”UPDATE
sensitive_table SET column1 = ‘value1’ WHERE id = 1″}}

# 查看权限变更操作
$ grep -i “GRANT” /mysql/logs/audit.log | tail -n 5
{“audit_record”:{“name”:”Query”,”recorded_time”:”2026-04-07T23:00:20″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”app_user”,”priv_user”:”app_user”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:””,”sql_text”:”GRANT
SELECT ON fgedudb.* TO ‘new_user’@’localhost’ IDENTIFIED BY ‘new_password'”}}

# 查看登出事件
$ grep -i “Disconnect” /mysql/logs/audit.log | tail -n 5
{“audit_record”:{“name”:”Disconnect”,”recorded_time”:”2026-04-07T23:00:30″,”server_id”:1,”status”:0,”connection_id”:123,”user”:”app_user”,”priv_user”:”app_user”,”os_login”:””,”proxy_user”:””,”host”:”localhost”,”ip”:””,”db”:”fgedudb”}}

# 5. 使用Performance Schema查询审计数据
# 查询最近的修改操作
mysql> SELECT
THREAD_ID,
EVENT_ID,
TIMER_START,
SQL_TEXT
FROM

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息