Engineering Atlas › System Design Fundamentals

Three-phase commit and what it fixes

12 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

The problem it targets

In 2PC, a participant that voted yes and then lost the coordinator is uncertain. It cannot commit, because someone may have voted no. It cannot abort, because the coordinator may have decided commit and some participant may already have committed. The root cause is that a participant can go straight from "I voted yes" to "committed", so a survivor in the uncertain state cannot rule out that someone else committed.

The three phases

Dale Skeen introduced the protocol in 1981 as a fix for exactly this uncertainty (Skeen 1981).

  1. CanCommit: the coordinator asks each participant whether it can commit. Each replies yes (entering uncertain) or no (aborting).
  2. PreCommit: if all voted yes, the coordinator sends PRECOMMIT. Each participant enters pre-committed, durably records it, and acknowledges. If any voted no or timed out, the coordinator sends ABORT.
  3. DoCommit: once enough participants acknowledge the pre-commit, the coordinator sends DOCOMMIT and they commit.

The pre-committed state means "everyone voted yes and the decision is commit, but I have not committed yet". No participant ever commits while another is still uncertain, because commit is only sent after pre-commits are acknowledged.

Recovery without the coordinator

If the coordinator fails, surviving participants elect a new coordinator, which collects their states and applies a termination rule:

Timeouts follow the same logic: a participant waiting for PRECOMMIT that hears nothing aborts; a participant waiting for DOCOMMIT that hears nothing commits.

Where it breaks

The rule "all reachable are uncertain, so abort" assumes the unreachable ones are crashed, not alive on the other side of a partition. Suppose the coordinator sends PRECOMMIT to participant A, then the network splits A from B and C. A's side sees a pre-committed node and commits. B and C's side sees only uncertain nodes and aborts. The transaction is now committed on one side and aborted on the other, which violates atomicity. 3PC is correct in a synchronous system with crash failures, but real networks are asynchronous: you cannot distinguish a crashed node from a slow or partitioned one. Skeen's original analysis explicitly assumed the network never fails (Skeen 1981), and Kleppmann's Cambridge course skips 3PC altogether because it depends on the unrealistic synchronous model (Cambridge notes). Consensus protocols escape the trap by deciding with majorities rather than by guessing who has failed.

Quorum variants close the split-outcome hole. Skeen's 1982 quorum-based commit protocol only lets a side that holds a quorum commit or abort, so the minority side waits instead of guessing. It can still get stuck with a connected quorum that cannot make progress, which Keidar and Dolev's Enhanced 3PC (E3PC, 1998) fixes so that any connected quorum can always finish (Wikipedia). Note the price: a partitioned minority blocks again, which is exactly 2PC's behaviour for those nodes.

Cost

3PC adds a full round trip and an extra durable write per participant compared with 2PC, raising lock hold time by roughly 50%, in exchange for a guarantee that holds only under assumptions most deployments do not meet.

Down the stack

Layer 1The contract

3PC promises atomicity plus non-blocking termination, but only under a stated failure model: nodes fail by crashing and stay down (fail-stop), message delay is bounded by a known Δ, and a timeout therefore means the peer really crashed. Under those assumptions, any group of surviving participants can reach the outcome without waiting for the failed ones. Outside them (partitions, long pauses, unbounded delays) the contract offers no safety at all.

Layer 2The mechanism

The message flow is CanCommit? answered by Yes or No, then PreCommit answered by Ack, then DoCommit answered by HaveCommitted. Every state change is written to the participant's log before it replies, so a restarted participant knows whether it was uncertain or pre-committed. Skeen's analysis gives the design rule behind the extra phase: a protocol is non-blocking if and only if no local state is "adjacent" to both commit and abort, meaning no state from which another participant could already be committed while this one might still abort, and no state that is not yet committable sits adjacent to a commit state (Skeen 1981). In 2PC the prepared state violates this rule; 3PC's pre-committed state exists to fix it. On coordinator failure, survivors elect a backup coordinator (for example, the lowest live id), which polls states, applies the termination rule, and drives everyone to the result. Timeouts are derived from Δ, typically waiting about 2Δ for a reply.

Layer 3The machine

The bounded-delay assumption fails on real hardware in ordinary ways. A JVM full garbage collection can pause a process for hundreds of milliseconds to several seconds. Hypervisors steal CPU and live-migrate VMs with pauses of similar size. Linux TCP retransmission timeouts start around 200 ms on a live connection and back off exponentially; the standard sets the initial timeout before any measurement at 1 second and requires it to double on each expiry (RFC 6298), so one lost packet can delay a message by seconds. A failed top-of-rack switch leaves every node healthy but unreachable, which no timeout can tell apart from a crash. The extra phase also has a hardware cost: three forced log writes per participant instead of two, and six one-way messages per participant instead of four, so lock hold time rises by about half.

Why it's built this way

  1. 2PC blocks because an uncertain participant cannot rule out that someone already committed.
  2. Inserting a pre-commit state ensures nobody commits until everybody has left the uncertain state, so survivors can decide by looking at each other.
  3. Deciding without the failed nodes requires knowing they really failed, which only timing can tell.
  4. Timing is reliable only in synchronous networks, and real networks are asynchronous, so 3PC's safety rests on a false premise.
  5. Majority-based protocols do not need to know who failed, which is why Paxos Commit and consensus-replicated coordinators replaced 3PC in practice. Paxos Commit matches 2PC's disk-write delay in the normal case and only adds messages (Gray and Lamport).

Diagram

stateDiagram-v2
    [*] --> Init
    Init --> Uncertain: vote yes
    Init --> Aborted: vote no or timeout
    Uncertain --> PreCommitted: PRECOMMIT
    Uncertain --> Aborted: ABORT or timeout
    PreCommitted --> Committed: DOCOMMIT or timeout
    Committed --> [*]
    Aborted --> [*]

Worked example

Three inventory shards (A, B, C) take part in a reservation across warehouses. Network round trips are 1 ms and each durable write is 2 ms.

In the wild

Trade-offs

OptionStrengthsWeaknessesChoose when
2PCSimple, safe under partitionsBlocks if coordinator failsCoordinator is reliable or replicated
3PCNon-blocking under crash-only, bounded-delay failuresUnsafe under partitions, extra round tripSynchronous networks with fail-stop nodes, which is rare
2PC with consensus-replicated coordinatorSafe and practically non-blockingNeeds a consensus layerDistributed databases
Paxos CommitNon-blocking with majority fault toleranceComplex, more messagesResearch-grade or custom transaction layers
SagasNo distributed locksEventual consistency, compensationsCross-service business workflows

Pitfalls in production

Leadership lens

Check yourself

  1. Why is it safe for survivors that are all uncertain to abort in 3PC, but not in 2PC?

    Show answer

    In 3PC nobody can commit until everyone has reached pre-committed, so all-uncertain proves no one committed; in 2PC a participant may already have received commit.

  2. How does a network partition break 3PC?

    Show answer

    Each side applies the termination rule to the nodes it can see, so a side with a pre-committed node commits while a side with only uncertain nodes aborts.

  3. Why do real systems replicate the 2PC coordinator instead of using 3PC?

    Show answer

    Consensus decides with a majority, which stays safe under partitions and asynchrony, while 3PC's safety depends on timing assumptions that real networks violate.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →