線上環境執行 `su - mysql` 突然報錯 `su: cannot set user id: Resource temporarily unavailable`。這不是 MySQL 本身的錯誤,而是 **作業系統層面的資源限制** 導致無法創建新進程/線程。本文還原完整排查過程,揭示 MySQL 線程模型與 Linux `nproc` 限制的隱性關係。
[root@dbmain ~]# su - mysql
su: cannot set user id: Resource temporarily unavailable
[root@dbmain ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
...
max user processes (-u) 25600
open files (-n) 1024
...
全域 `nproc=25600` 看似充足,但這是 **root 用戶** 的限制,非 `mysql` 用戶。
oracle soft nproc 2047
oracle hard nproc 16384
...
mysql soft nproc 500 <-- 核心發現:mysql 用戶硬限制僅 500
mysql hard nproc 500
mysql soft nofile 1024
mysql hard nofile 65536
**`mysql` 用戶 `nproc` (max user processes) 被硬限制在 500**。
[root@dbmain ~]# ps -ef | grep mysql
root 4733 1 0 10:30 ? 00:00:00 /bin/sh /usr/bin/mysqld_safe ...
mysql 4788 4733 0 10:30 ? 00:00:04 /usr/sbin/mysqld ...
root 15171 17507 0 13:26 pts/2 00:00:00 mysql -uroot -p
root 20792 17163 0 15:30 pts/1 00:00:00 grep mysql
僅見 1 個 `mysqld` 主進程 (PID 4788) 和幾個 client 連線,**進程數遠低於 500**,為何仍報錯?
[root@dbmain ~]# ls -l /proc/4788/task/ | wc -l
# 假設輸出 450+ (含主線程、IO 線程、Worker 線程、連線線程等)
[root@dbmain ~]# cat /proc/4788/status | grep Threads
Threads: 480
**MySQL 使用 `pthread` 實現多線程,每條連線、每個後台任務 (purge、page cleaner、redo log writer 等) 都是一個 Linux 任務 (LWP),全部計入用戶的 `nproc` 計數器。**
# 1. 調大 limits.conf
vim /etc/security/limits.conf
mysql soft nproc 10000
mysql hard nproc 10000
# 2. 重新登入生效 (或重啟 mysqld 服務)
su - mysql # 成功!
# 3. 同步調整 MySQL 參數 (防止配置超過 OS 限制)
# my.cnf
max_connections = 5000
thread_cache_size = 100
# 4. 系統級也要跟上
echo "* soft nproc 10000" >> /etc/security/limits.conf
echo "* hard nproc 10000" >> /etc/security/limits.conf
# /etc/systemd/system/mysql.service.d/override.conf
[Service]
LimitNPROC=10000
LimitNOFILE=65536
| 認知點 | 說明 |
|---|---|
| MySQL 線程 = Linux 任務 (LWP) | 每條連線、每個後台線程都佔用一個 `nproc` 槽位 |
| `max_connections` ≠ 實際最大並發 | 受限於 OS `nproc`、`nofile`、記憶體、CPU |
| `limits.conf` 對特定用戶生效 | `mysql` 用戶需單獨配置,不能只依賴 `*` 通配 |
| systemd 服務有獨立 Limit | `LimitNPROC`/`LimitNOFILE` 在 unit 中覆蓋 PAM 限制 |
| 排查命令 | `cat /proc/ |
# 1. /etc/security/limits.conf
mysql soft nofile 65536
mysql hard nofile 65536
mysql soft nproc 10000
mysql hard nproc 10000
# 2. /etc/systemd/system/mysqld.service.d/override.conf (或 mysql.service)
[Service]
LimitNOFILE=65536
LimitNPROC=10000
LimitMEMLOCK=infinity
# 3. my.cnf
[mysqld]
max_connections = 5000
thread_cache_size = 200
open_files_limit = 65536 # 需 ≤ OS nofile hard limit
table_open_cache = 4000
# 4. 內核參數 /etc/sysctl.conf
fs.file-max = 1000000
fs.nr_open = 1000000
vm.max_map_count = 262144
# 5. 重啟驗證
systemctl daemon-reload
systemctl restart mysqld
su - mysql -c "ulimit -a" # 確認 nproc/nofile 生效
mysql -e "SHOW VARIABLES LIKE 'max_connections'; SHOW GLOBAL STATUS LIKE 'Threads_connected';"
**「Resource temporarily unavailable」看似神秘,實則是「MySQL 線程模型 + Linux nproc 限制」的必然碰撞。** 將 OS 級資源限制納入 MySQL 容量規劃與部署標準化清單,才能徹底根治此類隱性故障。