ERROR: canceling statement due to statement timeout は、1つの SQL の実行時間が、statement_timeout の設定を超えたので、PostgreSQL が SQL を取り消したときのエラーです。 SQLSTATE は 57014 です。

直す前に、次の2つを確かめます。

確かめること 方法 分かること
① 設定はどこで決まっているか SELECT setting, source FROM pg_settings WHERE name = 'statement_timeout' ロール・DB・接続・SQL のどこで設定されたか
② SQL が遅いのか、ロックを待っていたのか エラーの CONTEXT、pg_stat_activity の wait_event_type 遅いなら SQL を速く、ロック待ちなら止めている相手を探す

タイムアウトの値を延ばすのは、最後の手段です。ロック待ちが原因なら、延ばしても待つ時間が長くなるだけです。

確認環境:PostgreSQL 16.15、psycopg 3.3.6 で再現しました(確認日 2026年10月11日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「statement timeoutの直し方|PostgreSQL」

再現

SHOW statement_timeout;     -- 2s
SELECT pg_sleep(3);
ERROR:  57014: canceling statement due to statement timeout

Python(psycopg 3)では、psycopg.errors.QueryCanceled(sqlstate 57014)として受け取れました。公式ドキュメントによると、statement_timeout は単位を書かなければミリ秒で、0(既定)なら無効です。

① 設定がどこで決まっているかを探す

「設定した覚えがないのにタイムアウトする」ときは、pg_settings の source 列を見ます。

SELECT name, setting, unit, source FROM pg_settings
WHERE name IN ('statement_timeout', 'lock_timeout', 'idle_in_transaction_session_timeout');
設定のしかた 確認環境での source
ALTER ROLE tx SET statement_timeout = '2s' user
ALTER DATABASE reldemo SET statement_timeout = '4s' database
接続のときに指定(PGOPTIONS="-c statement_timeout=1500"、接続文字列の options) client
接続してから SET statement_timeout = '5s' session
何も設定していない default(0)

ロールと DB の両方に設定したときは、ロールの設定(2s)が使われ、source は user でした。 ロール・DB に付けた設定の一覧は、次の SQL で見られます。

SELECT r.rolname, d.datname, s.setconfig
FROM pg_db_role_setting s
LEFT JOIN pg_roles r ON r.oid = s.setrole
LEFT JOIN pg_database d ON d.oid = s.setdatabase;
 rolname | datname |       setconfig
---------+---------+------------------------
 tx      |         | {statement_timeout=2s}

公式ドキュメントでは、statement_timeout を postgresql.conf に書くことは、すべてのセッションに影響するため推奨しないとされています。アプリのフレームワーク・接続プールの設定(接続文字列の options など)で付いていることもあるので、client と表示されたらアプリの設定を探します。

② 遅い SQL か、ロック待ちかを見分ける

別の接続で行を UPDATE したまま(トランザクションを閉じずに)、同じ行を UPDATE しました。

ERROR:  57014: canceling statement due to statement timeout
CONTEXT:  while updating tuple (0,6) in relation "st_acc"

CONTEXT: while updating tuple ... in relation "st_acc" が付いていたら、行のロックを待っている間にタイムアウトしたと読めます。pg_sleep だけの遅い SQL では、CONTEXT は付きませんでした。

止めている相手を pg_stat_activity で探す

SELECT pid, application_name AS app, state, wait_event_type AS wtype, wait_event,
       pg_blocking_pids(pid) AS blocked_by, left(query, 40) AS query
FROM pg_stat_activity
WHERE datname = 'reldemo' AND pid <> pg_backend_pid();
 pid  |   app   | state  |  wtype  |  wait_event   | blocked_by
------+---------+--------+---------+---------------+------------
 1841 | batch_a | active | Timeout | PgSleep       | {}
 1845 | web_b   | active | Lock    | transactionid | {1841}
列 読み方
wait_event_type = Lock ロックを待っている(web_b)
blocked_by = {1841} pid 1841(batch_a)に止められている
wait_event_type が空 待たずに動いている(SQL そのものが遅い)

ロック待ちが原因なら、直すのは止めている側(batch_a)です。長いトランザクションを短くする、ロックを取る順番をそろえる、などを検討します。application_name を接続ごとに付けておくと、どのプログラムかが分かります。

lock_timeout との違い

lock_timeout = '1s' を付けて、同じロック待ちを起こしました。

ERROR:  55P03: canceling statement due to lock timeout
CONTEXT:  while updating tuple (0,6) in relation "st_acc"
設定 何を測るか エラー SQLSTATE
statement_timeout SQL 全体の時間 canceling statement due to statement timeout 57014
lock_timeout ロックを待つ時間だけ canceling statement due to lock timeout 55P03
idle_in_transaction_session_timeout トランザクションの中で何もしない時間 セッションが切られる ―

公式ドキュメントでは、statement_timeout が 0 でないとき、lock_timeout を同じか大きい値にしても意味がない(先に statement_timeout が来るため)と説明されています。lock_timeout を短め、statement_timeout を長めにすると、エラーの種類で原因を見分けられます。

idle_in_transaction_session_timeout は、トランザクションを開いたまま放置する接続を切ります。 公式ドキュメントでも、ロックを長く持ち続けるのを防ぐ用途が挙げられています。上の batch_a のような接続への対策になります。

一部の処理だけ、タイムアウトを延ばす(SET LOCAL)

夜間の集計だけ長くしたい、といった場合は、トランザクションの中で SET LOCAL を使います。

BEGIN;
SET LOCAL statement_timeout = '30min';     -- このトランザクションの中だけ
-- 時間のかかる集計
COMMIT;
SHOW statement_timeout;                    -- 元の値に戻っている
確認環境での動き 結果
SET LOCAL statement_timeout = '1s' のあと pg_sleep(2) タイムアウト。ROLLBACK 後は元の 5s に戻った
SET LOCAL statement_timeout = 0 のあと pg_sleep(6) 成功。COMMIT 後は元の 5s に戻った
トランザクションの外で SET LOCAL WARNING: SET LOCAL can only be used in transaction blocks、値は変わらない

SET(LOCAL なし)は、その接続を使い続ける限り残ります。 接続プールでは、次にその接続を使う別の処理にも影響するので、SET LOCAL を使います。

遅い SQL を速くする

ロック待ちでなかった場合は、SQL そのものを見直します。

確かめること 方法
実行計画 EXPLAIN (ANALYZE, BUFFERS) SQL
索引が使われているか 実行計画の Seq Scan
一度に扱う行が多すぎないか 小分け(1万件ずつなど)

確認の手順(チェックリスト)

順番 確認すること 方法
1 設定の値と出どころ pg_settings の setting・source
2 ロール・DB の設定 pg_db_role_setting
3 ロック待ちか CONTEXT: while updating tuple、wait_event_type = Lock
4 止めている相手 pg_blocking_pids(pid)
5 遅い SQL なら EXPLAIN (ANALYZE, BUFFERS)
6 延ばすなら SET LOCAL で、その処理だけ

よくある質問

Q. デッドロックのエラーとは違いますか。 A. 違います。デッドロックは、お互いが相手を待つ状態を PostgreSQL が見つけて、片方を止めるエラーです。タイムアウトは、待つ時間(実行時間)が設定を超えたときのエラーです。MySQL のデッドロックは、関連記事の「MySQL Deadlock foundの原因と対処|1213・1205」で扱っています。

まとめ

  • SQL の実行時間が statement_timeout を超えたエラー(57014)
  • pg_settings の source で、ロール・DB・接続・SQL のどこで設定されたかが分かる
  • CONTEXT: while updating tuple はロック待ち。pg_blocking_pids で止めている相手を探す
  • lock_timeout(55P03)を短めにすると、原因を見分けやすい
  • 延ばすなら SET LOCAL(トランザクションの外では効かない)

参考・出典

確認日はいずれも 2026年10月11日です。

  • PostgreSQL 16 文書「Client Connection Defaults」(statement_timeout・lock_timeout):https://www.postgresql.org/docs/16/runtime-config-client.html
  • PostgreSQL 16 文書「SET」:https://www.postgresql.org/docs/16/sql-set.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「statement timeoutの直し方|PostgreSQL」

株式会社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で一緒に開発しながら、 成長を楽しみませんか?