mysql_secure_installation可非交互执行,但需配合debconf-set-selections(Ubuntu/Debian)或--script-mode/echo管道(CentOS/RHEL),且必须手动配置bind-address、密码策略、用户权限等未覆盖项。

直接用 mysql_secure_installation 脚本就能完成大部分基线加固,但它交互式运行、无法集成进自动化流程;真要无人值守,必须绕过交互、预置参数,并补足它没覆盖的关键项——比如绑定地址、密码策略、用户重命名、插件加载等。
如何让 mysql_secure_installation 非交互执行
该脚本默认阻塞等待输入,但 MySQL 5.7+ 支持通过环境变量或管道注入响应。最稳定的方式是用 expect 模拟交互,不过生产环境常禁用 expect;更轻量的做法是用 debconf-set-selections(Ubuntu/Debian)或预生成响应文件(CentOS/RHEL)。
- Ubuntu/Debian 下可提前设置 debconf 选项:
echo "mysql-server mysql-server/root_password password YourStrongPass123!" | sudo debconf-set-selectionsecho "mysql-server mysql-server/root_password_again password YourStrongPass123!" | sudo debconf-set-selections - CentOS/RHEL 下推荐用
mysql_secure_installation的 --script-mode(MySQL 8.0.28+ 才支持),旧版本只能用echo -e "...n\ny\ny\ny\ny" | sudo mysql_secure_installation,但顺序易错、容错差 - 注意:该脚本不会修改
bind-address或启用密码验证插件,这些必须后续手动配置
为什么 bind-address 和 port 必须在 mysqld 启动前配置
如果 MySQL 已监听 0.0.0.0:3306,哪怕你之后创建了严格用户权限,攻击者仍可能在认证前发起连接试探、触发未授权的协议握手,甚至利用早期握手阶段的漏洞(如 CVE-2015-3152)。加固必须前置到网络层。
- 编辑配置文件(
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf),在[mysqld]段落添加:bind-address = 127.0.0.1(仅本地)或bind-address = 192.168.10.5(仅指定内网IP)port = 3307(非默认端口,避开扫描器首轮探测) - 改完必须重启服务:
sudo systemctl restart mysqld,否则配置不生效 - 验证是否生效:
sudo ss -tlnp | grep :3307,确认监听地址不是*:3307
密码策略和用户最小权限怎么用 SQL 脚本批量落实
MySQL 5.7+ 的 validate_password 插件必须显式安装并设全局参数,且创建用户时才会校验——这意味着你得先装插件、再建用户,顺序不能反;而权限回收必须针对每个用户逐条执行,不能靠通配符一揽子处理。
- 加载插件(MySQL 8.0 默认已加载,但需确认):
INSTALL PLUGIN validate_password SONAME 'validate_password.so'; - 设策略(中等强度):
SET GLOBAL validate_password.policy = 'MEDIUM';SET GLOBAL validate_password.length = 12; - 创建应用用户(禁止远程、仅限库级权限):
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'HardP@ssw0rd#2026';GRANT SELECT, INSERT, UPDATE ON myapp_db.* TO 'app_user'@'localhost'; - 删掉危险组合:
DROP USER IF EXISTS ''@'localhost';DROP USER IF EXISTS 'root'@'%';
哪些操作必须人工核验,没法完全脚本化
脚本能跑完命令,但无法判断业务上下文是否合理。比如 bind-address = 127.0.0.1 对单机 Web 应用安全,但如果 PHP-FPM 运行在另一台机器上,这就直接导致连不上;又比如把 root 改名为 dba_admin 能防爆破,但所有运维文档、监控脚本、备份任务里的连接字符串都得同步更新,漏一处就中断。
真正卡点在于:脚本不知道你的网络拓扑、不知道谁在用哪个账号、也不知道哪些权限是历史遗留但实际已弃用。所以每次加固后,必须用真实业务链路验证登录、查询、写入——而不是只看 mysql -u app_user -p -e "SELECT 1" 返回 1 就算通过。


















