↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / Locks

FOR UPDATE

FOR UPDATE causes the rows retrieved by the SELECT statement to be locked as though for update. This prevents them from being locked, modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt UPDATE, DELETE, SELECT FOR UPDATE, SELECT FOR NO KEY UPDATE, SELECT FOR SHARE or SELECT FOR KEY SHARE of these rows will be blocked until the current transaction ends; conversely, SELECT FOR UPDATE will wait for a concurrent transaction that has run any of those commands on the same row, and will then lock and return the updated row (or no row, if the row was deleted). Within a REPEATABLE READ or SERIALIZABLE transaction, however, an error will be thrown if a row to be locked has changed since the transaction started. For further discussion see Data Consistency Checks at the Application Level. The FOR UPDATE lock mode is also acquired by any DELETE on a row, and also by an UPDATE that modifies the values of certain columns. Currently, the set of columns considered for the UPDATE case are those that have a unique index on them that can be used in a foreign key (so partial indexes and expressional indexes are not considered), but this may change in the future.

Reading PG 18·Select a recorded version

Compatibility

Compare different transactions holding locks on the same Row lock.

· Compatible modes

  • Conflicts with every mode in this scope.

View the full compatibility matrices

Commands acquiring this mode

SQL commandObject, phase and conditions
SELECT FOR UPDATELock selected rows, with ROW SHARE on the target table. NOWAIT and SKIP LOCKED affect waiting, not mode compatibility. Source
UPDATE (key update)Used when updating key columns of a unique index usable by a foreign key, excluding partial and expression indexes. Source
DELETELock rows being deleted, with ROW EXCLUSIVE on their table. Source
MERGE … WHEN MATCHED THEN DELETE / UPDATE (key)The matched action deletes a row or updates key columns. An insert-only action does not use this row lock. Source
INSERT … ON CONFLICT DO UPDATE (key)The conflict action updates key columns of an existing row. This is not a fixed row lock for every INSERT. Source

Other lock modes

conflicts
for-key-share, for-share, for-no-key-update, for-update

Definition PG 18

FOR UPDATE causes the rows retrieved by the SELECT statement to be locked as though for update. This prevents them from being locked, modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt UPDATE, DELETE, SELECT FOR UPDATE, SELECT FOR NO KEY UPDATE, SELECT FOR SHARE or SELECT FOR KEY SHARE of these rows will be blocked until the current transaction ends; conversely, SELECT FOR UPDATE will wait for a concurrent transaction that has run any of those commands on the same row, and will then lock and return the updated row (or no row, if the row was deleted). Within a REPEATABLE READ or SERIALIZABLE transaction, however, an error will be thrown if a row to be locked has changed since the transaction started. For further discussion see Data Consistency Checks at the Application Level. The FOR UPDATE lock mode is also acquired by any DELETE on a row, and also by an UPDATE that modifies the values of certain columns. Currently, the set of columns considered for the UPDATE case are those that have a unique index on them that can be used in a foreign key (so partial indexes and expressional indexes are not considered), but this may change in the future.

Compare versions

Complete source facts

commands

map[label:SELECT FOR UPDATE note:Lock selected rows, with ROW SHARE on the target table. NOWAIT and SKIP LOCKED affect waiting, not mode compatibility. slug:select source:map[kind:documentation path:doc/src/sgml/mvcc.sgml revision:753057e340da8f22e57c9a409ea7a235fd6a46bd sha256:4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340 url:https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/mvcc.sgml] source_url:https://www.postgresql.org/docs/18/explicit-locking.html variant:9c457e2f8f3c], map[label:UPDATE (key update) note:Used when updating key columns of a unique index usable by a foreign key, excluding partial and expression indexes. slug:update source:map[kind:documentation path:doc/src/sgml/mvcc.sgml revision:753057e340da8f22e57c9a409ea7a235fd6a46bd sha256:4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340 url:https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/mvcc.sgml] source_url:https://www.postgresql.org/docs/18/explicit-locking.html variant:1982fd8d6bd7], map[label:DELETE note:Lock rows being deleted, with ROW EXCLUSIVE on their table. slug:delete source:map[kind:documentation path:doc/src/sgml/mvcc.sgml revision:753057e340da8f22e57c9a409ea7a235fd6a46bd sha256:4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340 url:https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/mvcc.sgml] source_url:https://www.postgresql.org/docs/18/explicit-locking.html variant:a1f051f53cf5], map[label:MERGE … WHEN MATCHED THEN DELETE / UPDATE (key) note:The matched action deletes a row or updates key columns. An insert-only action does not use this row lock. slug:merge source:map[kind:documentation path:doc/src/sgml/mvcc.sgml revision:753057e340da8f22e57c9a409ea7a235fd6a46bd sha256:4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340 url:https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/mvcc.sgml] source_url:https://www.postgresql.org/docs/18/explicit-locking.html variant:8341438966ce], map[label:INSERT … ON CONFLICT DO UPDATE (key) note:The conflict action updates key columns of an existing row. This is not a fixed row lock for every INSERT. slug:insert source:map[kind:command-documentation path:doc/src/sgml/ref/insert.sgml revision:753057e340da8f22e57c9a409ea7a235fd6a46bd sha256:f93403779fb1d980cd5995a1e2741bbdae8404584407610f9aba33ec4724a39f url:https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/insert.sgml] source_url:https://www.postgresql.org/docs/18/sql-insert.html variant:211a0191f91b]

provenance

{"doc_slug":"18","fetched_at":"2026-09-27T09:39:42+00:00","label":"18","major":"18","official_url":"https://www.postgresql.org/docs/18/explicit-locking.html","ref":"REL_18_STABLE","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sources":[{"kind":"command-documentation","path":"doc/src/sgml/ref/alter_index.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"746cd43287186dfbfa6acf77fd5c6713e66919653fb00af5476a0baa65988e7a","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/alter_index.sgml"},{"kind":"command-documentation","path":"doc/src/sgml/ref/alter_table.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"10436673fa2f093bdf51986a06d22dd748a9bb003bcd5517db2a65fba569a3c9","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/alter_table.sgml"},{"kind":"command-documentation","path":"doc/src/sgml/ref/comment.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"d0048329d237192696d7ccb9471aba4137d943556fdb770e2ffb3cf6c511c18f","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/comment.sgml"},{"kind":"source","path":"src/backend/commands/copy.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"f50ecc1531109fc172d841d461e209cef611f3d017ef4184034c39e128deabbe","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/commands/copy.c"},{"kind":"command-documentation","path":"doc/src/sgml/ref/create_index.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"3698f11c6f447d127e4624a1a845dee4d5146b8337ddc6d895a7962e676717f8","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/create_index.sgml"},{"kind":"source","path":"src/backend/access/heap/heapam.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"bca2ca0746a1862016bdb416b8482441a7b16360f71afe5e4abf6dbae0fa0c72","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/access/heap/heapam.c"},{"kind":"source","path":"src/backend/catalog/index.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"98a4156a5c21ae856a3b583b633cdeb578a5b69910386c9f166d69fcb04ba2d0","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/catalog/index.c"},{"kind":"command-documentation","path":"doc/src/sgml/ref/insert.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"f93403779fb1d980cd5995a1e2741bbdae8404584407610f9aba33ec4724a39f","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/insert.sgml"},{"kind":"source","path":"src/backend/storage/lmgr/lock.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"e7f43560bf6a8417ff46991238084b6edeb44a995b87670ed1f7fa6f1515276b","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/storage/lmgr/lock.c"},{"kind":"documentation","path":"doc/src/sgml/mvcc.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"4b7bf77ee0af4b86052330ff2421d567df3604b75fe7d4f522bec84fdea87340","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/mvcc.sgml"},{"kind":"command-documentation","path":"doc/src/sgml/ref/reindex.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"5e889d6e1d9b09d5f9cd3f7086ca13f540da0fe8262cdd8a9037ce9aa6f1dfdf","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/reindex.sgml"},{"kind":"source","path":"src/backend/utils/adt/ri_triggers.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"a3fed49fbda88fe0fe5bcf35eb019fced28596ae4046233f2acb2eb9f90ab1da","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/utils/adt/ri_triggers.c"},{"kind":"source","path":"src/backend/commands/tablecmds.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"df8817816f893e73d5648fea169e222ba33320e5b24bf755b424b29098f4e7da","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/commands/tablecmds.c"},{"kind":"command-documentation","path":"doc/src/sgml/ref/vacuum.sgml","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"80ca5592cda7b74938385f84f09faac33574374c1a05d605a2d55982e4cf1bbf","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/doc/src/sgml/ref/vacuum.sgml"},{"kind":"source","path":"src/backend/access/heap/vacuumlazy.c","revision":"753057e340da8f22e57c9a409ea7a235fd6a46bd","sha256":"90932e3b1a7b57dda8f740807def59aedb57fbd0e2173e3af3309f145192c7c2","url":"https://raw.githubusercontent.com/postgres/postgres/753057e340da8f22e57c9a409ea7a235fd6a46bd/src/backend/access/heap/vacuumlazy.c"}],"status":"stable"}

summary

FOR UPDATE causes the rows retrieved by the SELECT statement to be locked as though for update. This prevents them from being locked, modified or deleted by other transactions until the current transaction ends. That is, other transactions that attempt UPDATE, DELETE, SELECT FOR UPDATE, SELECT FOR NO KEY UPDATE, SELECT FOR SHARE or SELECT FOR KEY SHARE of these rows will be blocked until the current transaction ends; conversely, SELECT FOR UPDATE will wait for a concurrent transaction that has run any of those commands on the same row, and will then lock and return the updated row (or no row, if the row was deleted). Within a REPEATABLE READ or SERIALIZABLE transaction, however, an error will be thrown if a row to be locked has changed since the transaction started. For further discussion see Data Consistency Checks at the Application Level.

Source references

Full definition and evidence JSON

Definition sources

center · PostgreSQL 18 · wiki-repair-20261023:5b7bf4985fa2adf08e1220846d0e4c7453eacf090f4368ec52d70ecf11659def

Text language: en · wiki-repair-20261023:5b7bf4985fa2adf08e1220846d0e4c7453eacf090f4368ec52d70ecf11659def