默认mysql.service未设内存/CPU/文件描述符限制及路径保护,易致资源耗尽或越权访问;LimitNOFILE与open_files_limit须同步配置,ProtectSystem和MemoryLimit等需按实际负载合理权衡。

为什么默认的 mysql.service 不能直接用于生产隔离
Debian 安装的 mysql-server 默认使用 /lib/systemd/system/mysql.service,它只设了 User=mysql 和基础重启策略,没限制内存、文件描述符、进程数或路径访问。这意味着:一个慢查询或大事务可能耗尽全部内存;临时表写入 /tmp 可能被其他服务干扰;错误日志或 socket 文件若落在共享路径,存在越权读写风险。
LimitNOFILE 和 open_files_limit 必须配对生效
只在 systemd 里设 LimitNOFILE=65535 不够——MySQL 启动时仍会按配置文件里的 open_files_limit 值初始化。两者不一致会导致 mysqld 启动失败或静默降级。
- 先确认 MySQL 实际支持的上限:
mysqld --verbose --help | grep "open files" - 在
/etc/mysql/my.cnf的[mysqld]段加:open_files_limit = 65535 - 在 systemd service 文件的
[Service]段加:LimitNOFILE=65535 - 如果用
mysqld_safe启动(不推荐),还要在mysqld_safe脚本里显式 ulimit
用 ProtectSystem 和 ReadOnlyPaths 锁死敏感路径
MySQL 进程不需要写 /etc、/boot 或 /root,但默认权限下它有完整读取能力。systemd 提供的路径保护机制可强制拒绝访问,比靠 SELinux 或 DAC 权限更轻量、更确定。
-
ProtectSystem=strict等价于将/usr、/boot、/etc全部只读挂载 -
ReadOnlyPaths=/etc /usr/lib/mysql/plugin可补充保护插件目录(防止恶意 UDF 加载) -
InaccessiblePaths=/proc/sys /sys/fs/cgroup阻止容器逃逸类操作(即使没跑在容器里) - 注意:若 MySQL 配置了
secure_file_priv指向/var/lib/mysql-files,这个路径必须出现在ReadWritePaths列表中
内存与 CPU 限制要避开 MySQL 内部管理逻辑
MySQL 自己管理 buffer pool、sort buffer 等内存区域,systemd 的 MemoryLimit 是 cgroup v2 级别硬限。一旦触发 OOM kill,mysqld 进程会被无条件终止,不会走 graceful shutdown 流程。
- 推荐做法:设
MemoryLimit=4G,同时在my.cnf中把innodb_buffer_pool_size设为3G,留出 1G 给连接线程、排序缓存等 - 避免设
MemoryLimit=2G+innodb_buffer_pool_size=2G—— buffer pool 分配失败时 mysqld 可能反复崩溃重启 - CPU 限制用
CPUQuota=75%比CPUSchedulingPolicy=other更可控,尤其在混部环境下防 CPU 抢占
真正难的是权衡:开太多保护(比如 PrivateDevices=true)可能让某些监控 agent 或备份工具失联;设太严的资源限值又会让高峰期连接直接被拒绝而不是排队等待。关键不是堆参数,而是根据 mysqld 实际运行时的 cat /proc/$(pidof mysqld)/status | grep -E "VmRSS|Threads" 数据反推合理边界。











