MySQL安全配置完全指南:从入门到生产环境加固

“数据库没有安全配置,就像把保险柜的钥匙挂在门上。”
—— 某位被黑过的DBA

写在前面:为什么MySQL安全配置如此重要?

我敲代码已经好些年头了,见过太多“数据泄露”的案例——不是黑客技术有多高明,而是最基本的安全配置都没做。默认端口没改、root密码是123456、匿名用户没删……这些漏洞就像开着大门等小偷来。

MySQL作为最流行的开源数据库,承载着无数网站和应用的“身家性命”。数据泄露、删库跑路、勒索攻击——这些风险离我们并不远。但好消息是,只要做好基础安全配置,80%的攻击都能防住

本教程将系统讲解MySQL安全配置的完整流程,从安装后的第一步加固,到生产环境的高级防护。无论你是刚装好MySQL的新手,还是负责数据库运维的开发者,都能从中找到可落地的方案。

📌 本文适用场景:
✅ 刚装好MySQL,不知道下一步该做什么
✅ 担心数据库被攻击,想加固安全
✅ 准备上线项目,需要做安全检查
✅ 学习数据库运维,系统了解安全配置

第一章:安装后的第一道防线——mysql_secure_installation

MySQL安装完成后,官方提供了一个“一键加固”脚本,这是新手最容易忽略但最重要的安全步骤。

1.1 运行安全脚本

在终端执行以下命令:

# CentOS/RHEL
sudo mysql_secure_installation

# Ubuntu/Debian
sudo mysql_secure_installation

脚本会引导你完成5项关键安全设置[citation:3]:

1. 设置root密码
   → 输入一个强密码(至少12位,含大小写字母+数字+特殊字符)

2. 删除匿名用户
   → 输入 y(这是默认存在的隐患,必须删除)

3. 禁止root用户远程登录
   → 输入 y(root只能从localhost登录,这是铁律)

4. 删除test测试数据库
   → 输入 y(测试数据库在生产环境是安全隐患)

5. 重新加载权限表
   → 输入 y(让所有更改立即生效)

✅ 新手友好提示: 如果你安装的是MySQL 8.0以上版本,root用户默认使用caching_sha2_password认证,安全脚本会自动适配,按提示操作即可。

第二章:账户与权限管理(核心安全基石)

MySQL官方文档明确指出:“要求所有MySQL账户都有密码。如果所有账户都有密码,使用他人账户连接就会变得困难得多。”[citation:1]

2.1 删除匿名用户

如果运行了安全脚本,这一步已经自动完成。如果没有,手动执行:

-- 查看是否存在匿名用户
SELECT User, Host FROM mysql.user WHERE User='';

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

2.2 禁止root远程登录

root账户是MySQL的“超级管理员”,永远不允许从远程连接。这是最基本也是最重要的安全原则[citation:7]。

-- 检查root的Host
SELECT User, Host FROM mysql.user WHERE User='root';

-- 如果Host是'%'或具体IP,改为localhost
UPDATE mysql.user SET Host='localhost' WHERE User='root';
FLUSH PRIVILEGES;

2.3 为每个应用创建专用用户

遵循最小权限原则:每个应用程序只能访问自己需要的数据[citation:2]。

-- 创建专用用户(只能从本地连接)
CREATE USER 'app_user'@'localhost' IDENTIFIED BY '强密码';

-- 只授予必要权限(例:只读)
GRANT SELECT ON my_database.* TO 'app_user'@'localhost';

-- 如果需要增删改,授予对应权限
GRANT SELECT, INSERT, UPDATE, DELETE ON my_database.* TO 'app_user'@'localhost';

-- 应用更改
FLUSH PRIVILEGES;

⚠️ 重要原则: 永远不要给应用用户授予SUPER或ALL PRIVILEGES权限。一个被SQL注入攻破的Web应用,如果连的数据库用户有SUPER权限,后果不堪设想。

2.4 禁用通配符主机

避免在用户Host字段中使用'%'通配符,这相当于把数据库暴露给全世界[citation:8]:

-- 查看所有用户的主机设置
SELECT User, Host FROM mysql.user;

-- 如果有'%'通配符,改为具体IP或localhost
UPDATE mysql.user SET Host='192.168.1.%' WHERE User='app_user' AND Host='%';
FLUSH PRIVILEGES;

2.5 定期清理过期用户

定期审查并删除不再使用的账户:

-- 查看所有用户
SELECT User, Host, authentication_string FROM mysql.user;

-- 删除废弃用户
DROP USER 'old_user'@'localhost';

第三章:网络层防护——把门关好

3.1 修改默认端口

默认端口3306是“公开的秘密”,修改端口可以降低被自动扫描工具发现的风险[citation:2][citation:8]。

# 编辑配置文件
vim /etc/my.cnf  # CentOS
# 或
vim /etc/mysql/mysql.conf.d/mysqld.cnf  # Ubuntu

# 在[mysqld]段中添加
port = 3506  # 选择一个非标准端口

# 重启MySQL
sudo systemctl restart mysqld

3.2 限制监听地址

如果数据库只供本机应用使用,设置bind-address为127.0.0.1,彻底切断远程连接[citation:3]。

# 配置文件
[mysqld]
bind-address = 127.0.0.1  # 仅本地访问

# 如果需要远程访问,设置为具体IP
bind-address = 192.168.1.100  # 只监听内网IP

# 如果确实需要公网访问,建议配合防火墙白名单
bind-address = 0.0.0.0  # 监听所有(不推荐,需配合严格防火墙)

3.3 防火墙配置

用防火墙只允许特定IP访问数据库端口[citation:11]:

# CentOS/RHEL (firewalld)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="3306" accept'
sudo firewall-cmd --reload

# Ubuntu (ufw)
sudo ufw allow from 192.168.1.0/24 to any port 3306 proto tcp
sudo ufw reload

# 查看已开放规则
sudo firewall-cmd --list-all  # CentOS
sudo ufw status              # Ubuntu

3.4 网络隔离

生产环境建议:数据库服务器与Web服务器分属不同子网,不暴露公网IP[citation:12]。

第四章:数据传输加密——SSL/TLS配置

数据库与客户端之间的数据传输是明文的,任何人只要在网络中监听就能看到SQL语句和数据[citation:1]。SSL/TLS加密可以解决这个问题。

4.1 生成SSL证书

# 创建证书存放目录
sudo mkdir -p /etc/mysql/ssl

# 生成私钥和自签名证书(测试环境)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/mysql/ssl/mysql-key.pem \
  -out /etc/mysql/ssl/mysql-cert.pem

# 生产环境建议使用CA签发的证书

4.2 配置MySQL启用SSL

# 配置文件添加
[mysqld]
ssl-ca=/etc/mysql/ssl/mysql-cert.pem
ssl-cert=/etc/mysql/ssl/mysql-cert.pem
ssl-key=/etc/mysql/ssl/mysql-key.pem

# 强制SSL连接(可选)
require_secure_transport=ON

# 重启MySQL
sudo systemctl restart mysqld

4.3 验证SSL是否生效

# 登录MySQL后执行
SHOW STATUS LIKE 'Ssl_cipher';

# 如果返回非空值,说明SSL已启用
# 查看SSL连接状态
SHOW STATUS LIKE '%ssl%';

4.4 强制用户使用SSL

-- 要求特定用户必须使用SSL连接
ALTER USER 'app_user'@'%' REQUIRE SSL;
FLUSH PRIVILEGES;

第五章:文件系统与权限控制

5.1 数据目录权限

MySQL官方强烈建议:确保唯一拥有数据库目录读写权限的Unix用户是运行mysqld的账户[citation:1]。

# 检查数据目录权限
sudo ls -la /var/lib/mysql/

# 设置正确的所有者
sudo chown -R mysql:mysql /var/lib/mysql

# 设置严格权限(仅所有者可读写)
sudo chmod -R 700 /var/lib/mysql

5.2 不以root用户运行MySQL

官方文档明确指出:“永远不要以Unix root用户运行MySQL服务器。这非常危险。”[citation:1]

# 配置文件指定运行用户
[mysqld]
user = mysql

# 验证
ps aux | grep mysqld
# 应该显示以mysql用户运行

5.3 限制文件操作权限

FILE权限非常危险,攻击者可以利用它读取系统中的任何文件[citation:1]:

-- 检查哪些用户有FILE权限
SELECT User, Host FROM mysql.user WHERE File_priv = 'Y';

-- 非管理员用户应该撤销此权限
REVOKE FILE ON *.* FROM 'app_user'@'localhost';

-- 限制文件读写目录(配置文件)
[mysqld]
secure_file_priv = /var/lib/mysql-files/

5.4 禁用符号链接

符号链接可能导致安全问题,建议禁用[citation:1][citation:8]:

# 配置文件
[mysqld]
skip_symbolic_links = yes  # MySQL 5.6+

5.5 禁用local_infile

禁用local_infile可以降低通过SQL注入读取敏感文件的风险[citation:8]:

# 配置文件
[mysqld]
local_infile = 0

第六章:日志与审计——事后追查能力

6.1 启用错误日志

# 配置文件
[mysqld]
log_error = /var/log/mysql/error.log

# 查看错误日志
sudo tail -f /var/log/mysql/error.log

6.2 启用慢查询日志

# 配置文件
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2  # 超过2秒的查询会被记录

# 查看慢查询
sudo tail -f /var/log/mysql/mysql-slow.log

6.3 通用查询日志(谨慎使用)

通用日志会记录所有操作,对性能有影响,建议仅在排查问题时临时开启[citation:7]:

# 动态开启(不重启)
SET GLOBAL general_log = ON;

# 配置文件(永久)
[mysqld]
general_log = 1
general_log_file = /var/log/mysql/mysql-general.log

6.4 审计日志(企业级功能)

MySQL Enterprise Audit可以记录谁在什么时间执行了什么操作[citation:2]。开源方案可以使用MariaDB Audit Plugin或第三方工具[citation:7]。

第七章:连接与资源限制

7.1 限制最大连接数

防止恶意攻击通过大量连接消耗服务器资源[citation:2]:

# 配置文件
[mysqld]
max_connections = 500  # 根据实际需求调整

# 限制单个用户的最大连接数
CREATE USER 'app_user'@'localhost' 
  IDENTIFIED BY 'password' 
  WITH MAX_USER_CONNECTIONS 50;

7.2 设置连接超时

# 配置文件
[mysqld]
wait_timeout = 600     # 空闲连接超时(秒)
interactive_timeout = 600

7.3 禁用skip-grant-tables

skip-grant-tables会跳过权限检查,仅在紧急恢复时使用,生产环境绝对禁用[citation:5]。

第八章:定期维护与更新

8.1 定期更新MySQL版本

MySQL官方会持续修复安全漏洞,及时更新是防止已知漏洞被利用的最有效方式[citation:2]。

# CentOS/RHEL
sudo yum update mysql-server

# Ubuntu/Debian
sudo apt update && sudo apt upgrade mysql-server

8.2 定期备份

# 全量备份
mysqldump -u root -p --all-databases > /backup/all-databases-$(date +%Y%m%d).sql

# 压缩备份
mysqldump -u root -p --all-databases | gzip > /backup/all-databases-$(date +%Y%m%d).sql.gz

# 定时备份(crontab)
0 2 * * * /usr/bin/mysqldump -u root -p'password' --all-databases | gzip > /backup/db-$(date +\%Y\%m\%d).sql.gz

8.3 定期审计权限

-- 查看所有用户及其权限
SELECT User, Host, 
  Select_priv, Insert_priv, Update_priv, Delete_priv, 
  Create_priv, Drop_priv, Grant_priv, Super_priv
FROM mysql.user;

-- 查看特定数据库的权限
SHOW GRANTS FOR 'app_user'@'localhost';

第九章:快速自查清单(上线前必查)

部署到生产环境前,对照以下清单逐项检查:

☐ 运行过 mysql_secure_installation
☐ 设置了强root密码(12位+,含特殊字符)
☐ 删除了匿名用户
☐ root用户只能从localhost连接
☐ 删除了test数据库
☐ 每个应用有独立数据库用户
☐ 应用用户遵循最小权限原则
☐ 没有用户使用'%'通配符主机
☐ 修改了默认端口3306(或严格防火墙)
☐ bind-address已正确设置
☐ 防火墙仅允许必要IP访问数据库端口
☐ 启用SSL/TLS加密
☐ MySQL以非root用户运行(user=mysql)
☐ secure_file_priv已设置
☐ 禁用local_infile
☐ 禁用symbolic_links
☐ 启用错误日志和慢查询日志
☐ 设置了合理的max_connections
☐ 定期备份方案已就绪
☐ MySQL版本已更新到最新稳定版

写在最后

数据库安全配置不是一次性工作,而是持续的过程。今天做完这些配置,只是迈出了第一步。后续还需要定期审查权限、监控异常连接、关注安全公告、及时打补丁。

我见过太多“裸奔”的数据库——默认端口、123456密码、匿名用户没删、远程root登录全开。说实话,这种配置被入侵不是“会不会”的问题,而是“什么时候”的问题。

花一个下午做完这些安全配置,可能就能避免一次让你彻夜难眠的数据泄露事故。这笔账,怎么算都划算。

今天这一篇,写给“刚装好MySQL还不太确定下一步做什么”的你。

“安全配置像买保险——希望永远用不上,但出事的时候能救命。”
—— 致所有认真对待数据安全的人


感谢你读到这里。
如果你按照本教程完成了MySQL安全配置,欢迎在评论区分享你的经验。