Skip to content

Dirty read

A dirty read is reading another transaction's uncommitted data. The danger is not that the data is fresh — it's that it may never become real: if the writer rolls back, you have read, and possibly acted on, a value that never existed.

Session A
Session B
BEGIN
BEGIN
UPDATE accounts SET balance = 999
SELECT balance→ 999 ← uncommitted data
ROLLBACK
acts on a balance that never existed

Formally this is Adya's G1a (aborted read). Its sibling G1b (intermediate read) is subtler — reading a draft the writer later overwrites before committing; both live in the anomaly catalog with the rest of the G1 family.

Who prevents it

LevelSQL standardPostgreSQLMySQL (InnoDB)
READ UNCOMMITTEDpermittedimpossible — the level silently behaves as READ COMMITTEDhappensproof
READ COMMITTED and uppreventedimpossibleprevented — proof

In PostgreSQL dirty reads are impossible at every level — READ UNCOMMITTED is accepted as syntax and silently upgraded. MySQL takes you at your word: its READ UNCOMMITTED hands out data that was never committed, which is why there is no good reason to run at that level.

  • Non-repeatable read — the committed-data cousin: nothing you read is dirty, yet repeated reads still disagree.
  • Intermediate read (G1b) — the dirty read's nastier variant: a draft value that no committed history ever contained.

See it happen

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