PostgreSQL『connection limit exceeded for non-superusers』の原因と対処
- 作成日 2025.09.24
- 更新日 2025.10.06
- その他
新規接続が上限に達し、一般ユーザー(非スーパーユーザー)の接続を受け付けられない状態で発生する。典型メッセージの読み方、発生条件、即効復旧(安全にセッションを開放)、恒久対策(接続数設計・プーリング・設定値の見直し)、クラウド環境での注意点までを体系化した。
- 1. エラーメッセージの読み方(代表例)
- 2. 発生条件の早見表
- 3. 最短復旧:まず管理者でログインするための枠を確保
- 4. 原因特定:接続の内訳を可視化
- 5. ロール/データベース単位の上限に達している場合の対処
- 6. アプリ側の基本設計:接続プールを正しく使う
- 7. 中間プール(PgBouncer等)の活用:コネクションを桁違いに削減
- 8. 放置セッション対策:タイムアウトとリーク防止
- 9. max_connections を上げる前に考えること
- 10. 複製/バックグラウンドが使うスロットの理解
- 11. クラウド環境(RDS/Aurora/Cloud SQLなど)での要点
- 12. “いま切ってよい接続”の安全な選別クエリ集
- 13. 再発防止の設計チェックリスト
- 14. 最小再現→解消の通し例
エラーメッセージの読み方(代表例)
FATAL: connection limit exceeded for non-superusers
FATAL: remaining connection slots are reserved for non-replication superuser connections
・「max_connections に達したが、残りは superuser(と複製接続)用として予約」
・一般ユーザーでは新規接続できないため、まずは「管理者でログインできる枠」を確保する設計が重要
発生条件の早見表
□ サーバ全体の max_connections に達した
□ superuser_reserved_connections ぶんが確保されておらず、管理者枠が足りない
□ 役割(ROLE)またはデータベースごとの CONNECTION LIMIT を超過
□ 接続プールの誤設定(アプリ側/中間層)がスパイクで接続を張り続ける
□ idle / idle in transaction の放置セッションが堆積
□ バックグラウンドワーカーや autovacuum、複製(WAL sender)もスロットを使用
最短復旧:まず管理者でログインするための枠を確保
-- postgresql.conf(またはパラメータグループ)で予約枠を設定
superuser_reserved_connections = 3 -- 例:管理用に3スロット確保
-- ↑反映には再起動が必要(クラウドは再起動/適用が別途必要)
-- いまログインできるなら、不要接続を終了して枠を空ける
SELECT pid, usename, application_name, state, backend_start
FROM pg_stat_activity
ORDER BY backend_start;
-- 安全に切ってよい候補(例:長時間 idle だが tx でない)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND state = 'idle'
AND backend_type = 'client backend'
AND usename IN ('appuser'); -- 影響範囲を限定・「idle in transaction」はトランザクションを開いたまま放置のため、業務影響に注意して個別判断
・autovacuum/複製/バックグラウンドは基本的に切らない
原因特定:接続の内訳を可視化
-- 総数・ユーザー別・アプリ別
SELECT
count(*) AS total,
count(*) FILTER (WHERE state = 'active') AS active,
count(*) FILTER (WHERE state LIKE 'idle%') AS idle
FROM pg_stat_activity;
SELECT usename, count(*)
FROM pg_stat_activity GROUP BY usename ORDER BY 2 DESC;
SELECT application_name, count(*)
FROM pg_stat_activity GROUP BY application_name ORDER BY 2 DESC;
-- 役割/DBごとの接続上限(-1は無制限)
SELECT rolname, rolconnlimit FROM pg_roles ORDER BY rolname;
SELECT datname, datconnlimit FROM pg_database ORDER BY datname;
-- 現在の上限と予約枠
SHOW max_connections;
SHOW superuser_reserved_connections;ロール/データベース単位の上限に達している場合の対処
-- 役割(ユーザー)単位の上限を見直す
ALTER ROLE appuser CONNECTION LIMIT 50; -- -1 は無制限
-- データベース単位の上限
ALTER DATABASE mydb CONNECTION LIMIT 200;
-- 一時的に解放する(該当ロール/DBの不要接続を終了)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'appuser' -- または datname='mydb'
AND pid <> pg_backend_pid();・上限緩和は“根本”ではない。アプリやプールの同時接続数と整合させることが本筋
アプリ側の基本設計:接続プールを正しく使う
# 例:Java/HikariCP
maximumPoolSize=30
minimumIdle=5
idleTimeout=300000
# → DB側の max_connections から管理/他サービス/バッチ/メンテ枠を差し引き、
# 合算で超えないよう各アプリのプール上限を配分
# 例:Node.js (pg-pool)
new Pool({ max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000 });
# 例:Ruby on Rails
pool: 10 # DB1台に対しアプリプロセス総数×pool <= 設計上限・プロセス/コンテナのスケールアウト時に合算で上限超過しやすい
・「リクエスト数=接続数」にならないよう、プールで多重化を吸収
中間プール(PgBouncer等)の活用:コネクションを桁違いに削減
# PgBouncer(transaction poolingの例)
[databases]
mydb = host=127.0.0.1 dbname=mydb
[pgbouncer]
pool_mode = transaction ; tx単位でサーバ接続を使い回す
max_client_conn = 2000 ; クライアント総数
default_pool_size = 50 ; DBへの実接続上限(合算設計の要)
server_idle_timeout = 30s
server_reset_query = DISCARD ALL・長時間接続しっぱなしのアプリでも、DBへの実接続数を小さく保てる
・セッション変数を多用する場合は session pooling との相性を検討
放置セッション対策:タイムアウトとリーク防止
-- 取引放置の自動切断
SET idle_in_transaction_session_timeout = '5min'; -- postgresql.confでも可
-- クライアント側のソケット生存確認(OS/Driver設定)
-- tcp_keepalives_idle / tcp_keepalives_interval / tcp_keepalives_count を適切化
SHOW tcp_keepalives_idle;・フレームワーク側でも“接続返却忘れ”を監視(finally/ensureでclose)
・LB/NGWのアイドル切断との相性にも注意
max_connections を上げる前に考えること
# postgresql.conf(一例)
max_connections = 300
superuser_reserved_connections = 3・単純増加はプロセス/メモリ消費の増大を招く(バックエンド1本=OSプロセス)
・work_mem は「接続×演算」単位で消費しうるため、上げすぎるとスワップ/OS圧迫の原因
・まずはプールで収容し、やむを得ない場合に限り段階的に増やす
複製/バックグラウンドが使うスロットの理解
-- 複製送信枠
SHOW max_wal_senders;
-- バックグラウンドワーカーの存在(参考)
SELECT * FROM pg_stat_activity
WHERE backend_type NOT IN ('client backend');・WAL sender や logical replication も接続を使う
・メンテ中の一時ジョブやETLが想定以上に接続を開くことがある
クラウド環境(RDS/Aurora/Cloud SQLなど)での要点
-- 設定反映は「パラメータグループ」や「DBフラグ」を変更し、適用/再起動が必要
-- 監視はpg_stat_activityに加え、サービス固有メトリクス(接続数/エラー)を併用
-- メンテナンスウィンドウ中の自動フェイルオーバーで接続嵐が起きないよう、
-- クライアント側の接続リトライ/バックオフを実装・マネージドでは max_connections の上限がインスタンスタイプ依存
・プーリング(PgBouncer on sidecar/Proxy)を標準構成にするのが無難
“いま切ってよい接続”の安全な選別クエリ集
-- 1) 長時間 idle のクライアント接続候補(30分以上アイドル)
SELECT pid, usename, application_name, client_addr, state, now()-state_change AS idle_for
FROM pg_stat_activity
WHERE state = 'idle' AND now()-state_change > interval '30 minutes'
ORDER BY idle_for DESC;
-- 2) アプリ特定(例:古いリビジョン)だけを終了
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE application_name = 'myapp-old'
AND state LIKE 'idle%';
-- 3) 自分自身/重要バックグラウンドを除外
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND backend_type = 'client backend'
AND state LIKE 'idle%';再発防止の設計チェックリスト
□ superuser_reserved_connections > 0 を確保(緊急用ログイン枠)
□ アプリ全体の“合算プール上限”がDB側の設計値を超えない
□ スパイク時のバックオフ/リトライ(指数的バックオフ+Jitter)
□ idle_in_transaction_session_timeout を有効化
□ PgBouncer等の中間プールを導入(transaction pooling を優先検討)
□ 役割/DBの CONNECTION LIMIT を正しく設定し、誤爆を防ぐ
□ 接続監視ダッシュボード(pg_stat_activity 集計)を常設
最小再現→解消の通し例
-- 準備:小さめの上限(テスト用)
ALTER SYSTEM SET max_connections = 20;
ALTER SYSTEM SET superuser_reserved_connections = 2;
SELECT pg_reload_conf(); -- サービスによっては再起動が必要
-- 疑似的に大量接続(別端末/pgbench -C など)を発生させると…
-- 一般ユーザーでの新規接続が失敗:
-- FATAL: connection limit exceeded for non-superusers
-- 対処1:不要な idle を解放
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state='idle' AND backend_type='client backend' AND pid<>pg_backend_pid();
-- 対処2:役割上限の見直し(必要な場合)
ALTER ROLE appuser CONNECTION LIMIT 30;
-- 対処3:PgBouncer(transaction pooling)経由に切替
-- (default_pool_size を 20程度に設定し、DB実接続を抑制)-
前の記事
PostgreSQL『ERROR: cannot change name of input parameter in FUNCTION』の原因と対処 2025.09.22
-
次の記事
PostgreSQL『ERROR: index row size exceeds maximum』の原因と対処 2025.09.24
コメントを書く