Multi-Version Concurrency Control
coreintermediateMVCC is the mechanism that lets PostgreSQL give every statement a consistent snapshot of the database without locking readers against writers — instead of one shared copy of each row that everyone fights over, PostgreSQL keeps multiple versions of a row around, and each transaction sees exactly the version(s) that existed as of its own snapshot.
Think of it as
Rather than one mutable row that must be locked to keep concurrent access safe, think of every write as adding a new, timestamped version alongside the old one, never erasing it outright. A reader's snapshot is really a rule for "which version of each row is mine to see" — old enough to have existed at the time, not yet superseded from that reader's point of view. Because a reader never needs to touch a row a writer is actively changing (it just looks at an earlier version instead), reading never blocks writing and writing never blocks reading — the core guarantee MVCC exists to provide.
What we're doing: Show a long-running reader and a concurrent writer both proceeding without blocking each other — the direct, observable consequence of MVCC.
- 3
- Session A's read acquires no lock that would block a writer -- this is MVCC's non-blocking read guarantee in action.
- 6–7
- Session B's write completes immediately, entirely unblocked by Session A's still-open read transaction.
- 10
- Session A's snapshot is unaffected by Session B's commit -- it is reading a different, still-valid row version.
-- Session B: UPDATE 1, COMMIT -- neither waited on Session A
-- Session A: still reads 1000Why this works: A traditional locking model would have Session B either wait for Session A's read lock to release, or Session A's later read would be forced to see Session B's uncommitted or newly-committed change depending on the locking scheme — MVCC sidesteps both problems by simply keeping the old row version around long enough for Session A's snapshot to keep using it.
Assuming MVCC means "no locking ever happens" in PostgreSQL
Wrong
Better
What you see: A developer is surprised when two concurrent UPDATE statements to the same row do block each other, having over-generalized "MVCC avoids blocking" to include writer-vs-writer conflicts, which MVCC never claimed to solve.
Why: MVCC's specific, documented guarantee is reader-vs-writer non-blocking — two genuine writers modifying the same row are still a real conflict that has to be resolved somehow, and PostgreSQL resolves it the ordinary way, by making the second writer wait for the first to finish.
- Row version 1 — existed before the UPDATE
- leads to Reader (old snapshot) (still visible to this snapshot)
- leads to Row version 2 (UPDATE creates a new version, does not overwrite)
- Reader (old snapshot) — keeps seeing version 1
- Row version 2 — created by a concurrent UPDATE
MVCC vs a naive single-copy-per-row model
Remember: MVCC gives every statement a consistent snapshot without locking readers against writers, by having a writer create a new row version instead of overwriting the old one in place — reading never blocks writing and writing never blocks reading. It does NOT mean writer-vs-writer conflicts on the same row stop existing; those still block as usual.
See also: updates create new row versions · transaction snapshots and visibility

