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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?