40001 — could not serialize access
PostgreSQL raises 40001 when a REPEATABLE READ or SERIALIZABLE transaction tries to update a row another transaction changed and committed after your snapshot began: it refuses the write rather than lose an update, and the fix is to retry the whole transaction.
Reproduce it
Two sessions. The -- [A] and -- [B] markers say who runs each statement, top to bottom.
-- [A] open a snapshot and read the row
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE id = 1; -- sees 100
-- [B] change that same row and commit
UPDATE accounts SET balance = 150 WHERE id = 1;
-- [A] now try to write the row you read
UPDATE accounts SET balance = 200 WHERE id = 1;A's last statement fails with ERROR: 40001: could not serialize access due to concurrent update. A's snapshot still shows 100, but the row is really 150 now, so writing 200 would silently erase B's change. Rather than let you lose that update, PostgreSQL aborts A. There's nothing to repair in the data, so you retry the transaction, and the second attempt reads the fresh value before it writes.
Run it yourself
This is the lead example on the Repeatable Read lesson, rendered there as a verified transcript against a real database. The retry loop that turns this failure into a safe write lives in Retrying serialization failures, and Serializable is the stricter level that raises the same 40001 for a wider set of conflicts.
The MySQL side
MySQL has no exact analog. InnoDB's SERIALIZABLE is lock-based rather than snapshot-based, so the same contention surfaces as a wait, not a serialization error. Depending on timing you'll hit a deadlock (1213) or a lock-wait timeout (1205) instead.