`Too many connections`、應用程式無法建立新連線、錯誤日誌顯示連線數達上限。
[mysqld]
max_connections = 5000 # 預設 151,視記憶體/負載調整
max_user_connections = 4000 # 單用戶上限,防單一應用佔滿
max_connect_errors = 100000 # 避免因錯誤嘗試導致 Host 被封鎖
配合 `mysqladmin variables` 確認生效,重啟 MySQL 服務。
預設 `wait_timeout = 28800` 秒 (8小時)。連線閒置超過此值,MySQL 主動斷開,導致連線池/持久連線應用報錯 (Communications link failure / Connection reset)。
[mysqld]
wait_timeout = 31536000 # 1 年 (秒)
interactive_timeout = 31536000 # 互動式客戶端同步調整
jdbc:mysql://host:3306/schema?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
以 Proxool 為例 (`proxool.xml`):
<proxool>
<alias>mysql</alias>
<driver-url>jdbc:mysql://localhost/yourDB?useUnicode=true&characterEncoding=UTF-8</driver-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<house-keeping-sleep-time>90000</house-keeping-sleep-time> <!-- 90 秒檢查一次 -->
<maximum-new-connections>20</maximum-new-connections>
<minimum-connection-count>3</minimum-connection-count>
<maximum-connection-count>20</maximum-connection-count>
<house-keeping-test-sql>SELECT 1</house-keeping-test-sql> <!-- 關鍵:定期驗證 -->
<test-before-use>true</test-before-use> <!-- 借用前驗證 -->
<test-after-use>true</test-after-use> <!-- 歸還後驗證 -->
</proxool>
其他連線池 (HikariCP、Druid、DBCP2、Tomcat JDBC Pool) 同理需啟用:
驗證:工作管理員結束 `mysqld.exe`,觀察服務自動拉起 (PID 變化)。
# systemd (現代發行版)
[Unit]
Description=MySQL Server
After=network.target
[Service]
Type=notify
ExecStart=/usr/sbin/mysqld
Restart=always
RestartSec=5
StartLimitInterval=60
StartLimitBurst=3
[Install]
WantedBy=multi-user.target
| 層面 | 關鍵設定 | 驗證方式 |
|---|---|---|
| MySQL 核心 | max_connections、wait_timeout、interactive_timeout | `SHOW VARIABLES LIKE '%timeout%'; SHOW STATUS LIKE 'Threads_connected';` |
| 應用/連線池 | autoReconnect / validationQuery / testOnBorrow / testWhileIdle | 模擬殺掉 DB 進程,觀察應用自動恢復無報錯 |
| 作業系統服務 | Windows: 服務復原=重啟(0分) / Linux: systemd Restart=always | `systemctl kill -s 9 mysqld` 或 Task Manager 結束進程 |
| 監控告警 | Threads_connected / max_connections 比率 > 80% 告警、服務重啟事件告警 | Prometheus + Grafana / Zabbix / Datadog |
MySQL 穩定運行三板斧:**核心參數給足余量、連線池務必驗證有效性、服務層面配置自動重啟**。單靠調大 `wait_timeout` 是治標不治本;**連線池驗證機制 (testOnBorrow + testWhileIdle) 才是通用、穩健、跨語言的終極解法**。