- MySQL
MySQL Too many connectionsの原因と直し方
ERROR 1040 (08004): Too many connections は、MySQL の同時接続数が上限(max_connections)に達し、新しい接続を受け付けられないときのエラーです。 上限を上げる前に、何が接続を使っているかを確かめます。多くの場合、原因は「使い終わった接続が閉じられずに残っている」ことです。
| 原因 | 見分け方 | 直し方 |
|---|---|---|
| 接続を閉じ忘れている(接続のもれ) | SHOW PROCESSLIST に Sleep の接続が大量 |
コードで必ず閉じる。コネクションプールを使う |
| サーバー台数 × プールの上限が多すぎる | アプリの台数を増やした直後に出た | プールの上限 × 台数 < max_connections にする |
| 遅い SQL で接続が詰まっている | Query の接続が多く、Time が大きい |
遅い SQL を直す |
| 本当にアクセスが多い | 上の3つに当てはまらない | max_connections を上げる(メモリも確認) |
確認環境:MySQL 8.0.46、Python 3.11(PyMySQL 2.2.8)(確認日 2026年10月11日)。max_connections を 5 にして再現しました(既定は 151)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「MySQL Too many connectionsの原因と直し方」
再現:接続を閉じ忘れる関数
import pymysql
conns = []
def fetch_user(uid):
c = pymysql.connect(host="localhost", user="dl", password="...", database="dl")
cur = c.cursor(); cur.execute("SELECT %s", (uid,)); r = cur.fetchone()
conns.append(c) # close() していない(接続が残り続ける)
return r
for i in range(1, 9):
fetch_user(i)
1回目: OK
2回目: OK
3回目: OK
4回目: OK
5回目: OK
6回目: (1040, 'Too many connections') ← 上限 5 に達した
7回目: (1040, 'Too many connections')
8回目: (1040, 'Too many connections')
$ mysql -u dl -p
ERROR 1040 (08004): Too many connections ← アプリと関係ない接続も入れない
1つの処理のもれで、DB を使うすべてのアプリ・ツールが接続できなくなります。
何が接続を使っているかを調べる
上限に達していても、CONNECTION_ADMIN 権限(または以前の SUPER 権限)を持つアカウントは、もう1本だけ接続できます(MySQL 公式マニュアル)。確認環境でも、一般ユーザーで 5 本使い切ったあと、管理用のアカウントで1本目は入れ、2本目は 1040 になりました。
SHOW STATUS LIKE 'Threads_connected'; -- 今の接続数
SHOW STATUS LIKE 'Max_used_connections'; -- 起動してからの最大の接続数
SELECT id, user, host, db, command, time, state
FROM information_schema.processlist ORDER BY id;
Threads_connected 6
Max_used_connections 6
id user host db command time state
46 dl localhost:46680 dl Sleep 1
47 dl localhost:46694 dl Sleep 1
48 dl localhost:46700 dl Sleep 1
49 dl localhost:46716 dl Sleep 0
50 dl localhost:46724 dl Sleep 0
55 admin2 localhost NULL Query 0 executing ← 予備の1本で入った管理者
command |
意味 | 多いときに疑うこと |
|---|---|---|
Sleep |
接続したまま、何もしていない | 閉じ忘れ、プールの持ちすぎ |
Query |
SQL を実行中 | 遅い SQL、ロック待ち |
host の列で、どのサーバー(アプリ)からの接続かが分かります。 ユーザー・ホストごとの数を数えると、どのアプリがもらしているかを絞り込めます。
SELECT user, substring_index(host, ':', 1) AS client, command, count(*) AS n
FROM information_schema.processlist GROUP BY 1, 2, 3 ORDER BY n DESC;
管理用のアカウントを先に用意しておく
予備の1本は、CONNECTION_ADMIN 権限を持つアカウントでしか使えません。アプリ用のアカウントには付けず、管理者用だけに付けておきます(公式マニュアルでも、通常のユーザーには付けないよう案内されています)。アプリが root で接続していると、予備の1本までアプリに使われてしまいます。
GRANT CONNECTION_ADMIN ON *.* TO 'admin'@'localhost';
直し方1:接続を必ず閉じる
def fetch_user(uid):
with pymysql.connect(host="localhost", user="dl", password="...", database="dl") as c: # 抜けると close される
with c.cursor() as cur:
cur.execute("SELECT %s", (uid,))
return cur.fetchone()
確認環境で、上限 5 のまま 20 回呼んでも、すべて成功しました。例外が起きても閉じられる書き方(Python の with、Java の try-with-resources、PHP は処理の終わりで閉じる)にします。
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT ...")) {
...
} // 例外が起きても close される(プールを使っていれば、プールに返る)
直し方2:コネクションプールの上限 × 台数を計算する
コネクションプール(HikariCP・SQLAlchemy の pool など)は、接続を使い回して、開きっぱなしにする仕組みです。プールの上限 × アプリの台数(プロセス数)が、MySQL の上限を超えないようにします。
| 構成 | 最大の接続数 |
|---|---|
| アプリ 1 台 × プールの上限 10 | 10 |
| アプリ 4 台 × プールの上限 10 | 40 |
| アプリ 4 台 × 1台あたり 4 プロセス × プールの上限 10 | 160(既定の 151 を超える) |
| +バッチ・管理ツール・監視 | さらに上乗せ |
サーバーを増やした・プロセス数を増やしたタイミングで出るなら、この計算が原因です。プールの上限を下げるか、max_connections を上げます。
wait_timeout を下げても、今つながっている接続には効かない
wait_timeout は、何もしていない接続(Sleep)を自動で切るまでの秒数です(確認環境の既定値は 28800 秒=8時間)。ただし、SET GLOBAL wait_timeout は、そのあとに接続した分にしか効きませんでした。
| 手順 | 結果 |
|---|---|
接続を 5 本開いてから SET GLOBAL wait_timeout = 3、5 秒待つ |
5 本とも残り、新しい接続は 1040 のまま |
SET GLOBAL wait_timeout = 3 のあとに 5 本開き、5 秒待つ |
5 本とも切られ、新しい接続ができた |
接続したときに、その接続の wait_timeout が決まるためです。今詰まっている接続を外すには、KILL 接続ID で個別に切るか、アプリを再起動します。切られた側の接続は、次に使ったときに Lost connection to MySQL server during query のエラーになりました。プールを使う場合は、プールの「接続の寿命」を wait_timeout より短くして、切られた接続を使わないようにします。
max_connections を上げる
原因を直したうえで、なお足りないなら上げます。
SET PERSIST max_connections = 300; -- 再起動後も残る(MySQL 8.0)
SET GLOBAL だけでは、再起動すると元に戻ります。設定ファイル(my.cnf の [mysqld])に書くか、SET PERSIST を使います。接続ごとにメモリを使うため、サーバーのメモリに余裕があるかも確かめます。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | 管理者で入る | CONNECTION_ADMIN を持つアカウント(予備の1本) |
| 2 | 何が接続しているか | information_schema.processlist を user・host・command で数える |
| 3 | Sleep が多いか |
閉じ忘れ、プールの持ちすぎ |
| 4 | プールの上限 × 台数 | max_connections を超えていないか |
| 5 | 今の接続を外す | KILL、またはアプリの再起動(wait_timeout の変更は今の接続に効かない) |
| 6 | 上限を上げる | SET PERSIST max_connections、メモリを確認 |
よくある質問
Q. 「Host '...' is blocked because of many connection errors」と出ます。
A. 別のエラーです。接続の失敗(途中で切れるなど)が続いたホストを、MySQL が締め出しています。FLUSH HOSTS(MySQL 8.0 では TRUNCATE TABLE performance_schema.host_cache)で解除し、失敗の原因を調べます。
Q. PHP で毎回接続していますが、閉じていません。
A. PHP は、通常はリクエストの処理が終わると接続を閉じます。ただし、持続的接続(PDO の PDO::ATTR_PERSISTENT)を使っていると、プロセスごとに接続が残ります。プロセス数 × 1 本で数えます。
まとめ
- 上限(既定 151)に達したエラー。上げる前に、何が使っているかを processlist で数える
Sleepが大量なら閉じ忘れ。with・try-with-resources で必ず閉じる- プールの上限 × 台数 × プロセス数が上限を超えていないか計算する
CONNECTION_ADMINを持つ管理者だけ、もう1本入れる。アプリには付けないSET GLOBAL wait_timeoutは、今つながっている接続には効かない- 上げるなら
SET PERSIST max_connections。メモリも確認する
参考・出典
確認日はいずれも 2026年10月11日です。
- MySQL 8.0 Reference Manual「Too many connections」:https://dev.mysql.com/doc/refman/8.0/en/too-many-connections.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「MySQL Too many connectionsの原因と直し方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。