Back to the map

Module 14 · Distributed transactions · Lesson 3 of 5

Three-phase commit

An attempt to remove 2PC's blocking by adding a pre-commit phase so participants can decide without the coordinator. Why it works under a synchronous network with crash failures only, why network partitions break it.

DeepNice-to-knowSenior 10 minPro Updated Nov 2026

Why it matters

Three-phase commit is the textbook answer to 2PC's blocking problem, and it appears in interviews mostly as a trap: candidates who present it as the fix reveal that they have not thought about partitions. Knowing precisely what it fixes, what it assumes, and why practitioners replaced the idea with consensus is the useful outcome of this lesson.

The idea

2PC blocks because a participant that voted yes cannot tell whether the coordinator decided commit or abort. Three-phase commit inserts a phase between the vote and the commit so that no participant is ever in a state where both outcomes remain possible for the group.

  1. 1

    Phase 1: can-commit

    The coordinator asks each participant whether it can commit; participants vote yes or no without yet writing redo records or locking for the long term.
  2. 2

    Phase 2: pre-commit

    If all voted yes, the coordinator sends pre-commit; participants prepare durably and acknowledge. Now every participant knows that every other participant voted yes, because pre-commit is only sent when they all did.
  3. 3

    Phase 3: do-commit

    The coordinator sends commit; participants commit and acknowledge.

The non-blocking property comes from this: if a participant has received pre-commit, it knows all votes were yes, so on coordinator failure the survivors can safely elect a new coordinator and commit. If a participant has not received pre-commit, no participant can have committed yet, so survivors can safely abort. There is no state in which some participants might have committed while others might have to abort, under the protocol's assumptions.

CoordinatorParticipants1 can-commit? → yes2 pre-commit → ack3 do-commit → ackcoordinator dies after 2: survivors all saw pre-commit → commitpartition: one side saw pre-commit, the other did not → they diverge
Pre-commit separates 'everyone voted yes' from 'commit'. After a coordinator failure, participants that saw pre-commit commit; those that did not abort. This only works if they can tell which group they are in.

The assumption that breaks it

3PC is non-blocking only under a synchronous model: bounded message delay and bounded processing time, so that a timeout reliably means a crash, and crash failures only, no partitions. Under a network partition, participants on one side may have received pre-commit (and proceed to commit) while participants on the other side timed out before receiving it (and abort). Both sides act correctly by the protocol and the result is a non-atomic outcome, which is worse than 2PC's blocking: 2PC blocked but stayed correct; 3PC stays live and becomes wrong. Since partitions are a fact of real networks, 3PC is essentially never deployed.

What replaced the idea

The modern approach keeps 2PC's correctness and removes the coordinator as a single point of blocking by replicating the coordinator's state with consensus. The commit decision is written to a Paxos or Raft group rather than one node's log, so coordinator failure is a leader failover measured in seconds and in-doubt participants can always learn the decision from the surviving majority. Spanner's 2PC over Paxos groups and Paxos Commit are this design. The extra network round of 3PC is replaced by the consensus round that makes the decision durable and available.

2PC3PC2PC over consensus
Blocking on coordinator failureYes, until it recoversNo, under synchronyOnly until the consensus group elects a new leader
Correct under partitionYes (blocks)No (can diverge)Yes (minority side blocks, majority continues)
Message rounds232 plus consensus rounds for the decision
Used in practiceYesEssentially neverYes: Spanner, CockroachDB, TiDB

What to take from it

The lesson of 3PC is general: a protocol's guarantees are only as good as its failure model. "Non-blocking" was bought by assuming timeouts are perfect failure detectors, which the earlier lessons showed they are not. Whenever a design claims to have removed a trade-off, ask what it assumes about the network.

Three-phase commit · Backplane