Skip to content

55P03 — canceling statement due to lock timeout

PostgreSQL raises 55P03 when a statement gives up waiting for a row lock, either because lock_timeout expired or because you asked for NOWAIT, canceling just that statement while the transaction lives on to retry.

Reproduce it

Two sessions want the same row. B caps how long it's willing to queue. The -- [A] and -- [B] markers say who runs each statement, top to bottom.

sql
-- [A] lock the row and hold it
BEGIN;
UPDATE accounts SET balance = 200 WHERE id = 1;

-- [B] wait at most 100ms for that lock, then give up
SET lock_timeout = '100ms';
UPDATE accounts SET balance = 300 WHERE id = 1;

B's update waits 100ms for A's lock, then fails with ERROR: 55P03: canceling statement due to lock timeout. Only that one statement was canceled, so B's transaction is still open and healthy: once A commits, B can rerun the update and succeed. The same 55P03 comes back immediately, with no waiting at all, when you write SELECT ... FOR UPDATE NOWAIT and the row is already locked.

Run it yourself

The NOWAIT, lock_timeout, SKIP LOCKED lesson renders this scenario as a verified transcript and lines up all three ways to refuse an open-ended wait. For the mechanics of the queue B is opting out of, read Lock queues and Row locks.

The MySQL side

MySQL splits this one code across two. A lock_timeout expiry maps to 1205 (innodb_lock_wait_timeout), and the NOWAIT fast-fail maps to 3572. Where PostgreSQL reuses 55P03 for both, InnoDB gives each its own number.

MIT Licensed · Every transcript on this site was generated by a real database run against MySQL 8.4.11 and PostgreSQL 18.4 at c52e5c9, and re-proven through psycopg and PyMySQL.