Three-Phase Commit
An extension of two-phase commit that adds a pre-commit phase to reduce the blocking window. Still not widely used in practice due to complexity; sagas are preferred.
What is Three-Phase Commit?
In short
Three-phase commit (3PC) is a distributed transaction protocol that commits or aborts an operation across multiple nodes by adding a "prepare to commit" step between the vote and the final commit, so participants can agree on the outcome without staying blocked if the coordinator crashes. It splits the commit into three rounds (canCommit, preCommit, doCommit) to remove the indefinite blocking that two-phase commit suffers from when the coordinator fails.
What it is
Three-phase commit is an agreement protocol that decides whether a transaction touching several machines should be committed everywhere or aborted everywhere. There is one coordinator and a set of participants (think a database node per shard). The whole point is atomicity: either every participant applies the change or none of them does, even though they are separate processes on separate machines.
It exists because of a known weakness in two-phase commit (2PC). In 2PC a participant votes yes, then waits for the coordinator to tell it commit or abort. If the coordinator crashes after collecting votes but before sending the decision, that participant is stuck. It cannot commit on its own (another node might have voted no) and it cannot abort (others might already be committing). It holds its locks and blocks, sometimes until an operator intervenes.
3PC inserts an extra round so that no participant is ever in a state where it does not know how to recover. The cost is one more network round trip and a lot more complexity, which is why it is studied far more often than it is shipped.
How it works under the hood
Phase 1, canCommit: the coordinator asks every participant whether it can commit. Each participant checks constraints, locks rows, and replies yes or no. Nobody has written anything permanent yet. A single no, or a timeout, leads straight to a global abort.
Phase 2, preCommit: if all votes were yes, the coordinator sends preCommit. Each participant acknowledges and records that the decision is going to be commit. This is the new middle state that 2PC lacks. The key property is that the protocol only reaches preCommit when it already knows no participant voted no, so a commit is now safe.
Phase 3, doCommit: the coordinator sends doCommit and participants finalize and release locks. The recovery rule is what makes 3PC non-blocking: if the coordinator dies, a participant that has reached preCommit can time out and commit anyway, because preCommit guarantees everyone agreed. A participant still in the canCommit state will time out and abort. Either way it acts without waiting forever.
The catch is the assumption behind that recovery rule. 3PC is non-blocking only under a synchronous model with reliable failure detection and no network partitions. In a real asynchronous network a partition can split nodes that timed out and committed from nodes that timed out and aborted, producing an inconsistent result. That is the practical reason it is rarely deployed.
When to use it and the trade-offs
Use a strong commit protocol like this only when you genuinely need atomic commit across nodes and cannot tolerate partial writes. For most application workloads you do not, because the latency cost of multiple synchronous round trips and held locks hurts throughput badly under load.
In practice teams reach for one of three alternatives. They keep 2PC and accept its blocking risk, often with a transaction manager and quick coordinator failover. They replace distributed atomic commit with a saga: a sequence of local transactions plus compensating actions that undo earlier steps if a later one fails, trading strict atomicity for availability and eventual consistency. Or they push the agreement problem down to a consensus protocol like Paxos or Raft, which gives a correct fault-tolerant decision and is what modern systems actually build on.
The honest summary is that 3PC solved the wrong half of the problem. It removed blocking but assumed away network partitions, and partitions are the failure that distributed systems must survive. Consensus-based commit (for example a commit protocol layered on Raft) gives you a fault tolerant decision without the false safety, so 3PC mostly survives as a teaching tool that explains why consensus is needed.
A concrete example
Imagine a banking transfer of 100 dollars where the source account lives on shard A and the destination on shard B. The coordinator runs canCommit: shard A checks the balance and locks the row, shard B locks the destination row, both reply yes. So far nothing is final and the money has not moved.
The coordinator sends preCommit and both shards acknowledge. Now suppose the coordinator crashes right here. Under 2PC both shards would sit on their locks indefinitely, freezing both accounts. Under 3PC each shard times out, sees that it reached preCommit, and independently commits the transfer, then releases its locks. The transfer completes without an operator.
The failure 3PC cannot handle is a partition during phase 3. If a network split leaves shard A able to commit while shard B is isolated and times out into abort, you end up with money debited from A but never credited to B. That single scenario is why systems such as Google Spanner and CockroachDB use Paxos or Raft for the commit decision instead of plain 3PC.
Where it is used in production
Google Spanner
Uses 2PC for cross-shard transactions but makes each participant a Paxos group, so the commit decision is fault tolerant and durable rather than relying on a 3PC style timeout.
CockroachDB
Layers distributed transactions on top of Raft consensus per range, getting the non-blocking, partition-safe commit that 3PC tried and failed to provide.
Apache ZooKeeper
Coordinates distributed agreement with the Zab consensus protocol, the practical replacement for ad hoc atomic-commit protocols like 3PC.
etcd
Backs Kubernetes with Raft based consensus to agree on cluster state changes instead of a multi-phase commit coordinator.
Frequently asked questions
- What problem does three-phase commit fix in two-phase commit?
- It removes the blocking case. In 2PC, if the coordinator crashes after participants vote yes but before it sends the decision, those participants hold their locks and cannot safely commit or abort on their own. 3PC adds a preCommit phase so a participant that has reached it can commit on a timeout, and one that has not can abort, instead of waiting forever.
- Is three-phase commit actually non-blocking?
- Only under strong assumptions: a synchronous network, an upper bound on message delay, and no partitions. In a real asynchronous network with partitions, 3PC can produce an inconsistent result, with some nodes committing and others aborting. That is why it is considered non-blocking in theory but unsafe in practice.
- Why do real systems not use three-phase commit?
- Two reasons. It adds an extra synchronous network round trip and more held locks, hurting latency and throughput, and its safety guarantee breaks under network partitions, which are the exact failures distributed systems must survive. Consensus protocols like Paxos and Raft give a correct fault tolerant commit decision instead, so teams build on those.
- What is the difference between 3PC and a saga?
- 3PC tries to keep one atomic transaction across nodes, holding locks until everyone agrees. A saga gives that up: it runs a series of independent local transactions and, if a later step fails, runs compensating actions to undo the earlier ones. Sagas trade strict atomicity for availability and are far more common in microservices.
- How many round trips does 3PC need compared to 2PC?
- 2PC needs two coordinator round trips: collect votes, then send the decision. 3PC needs three: canCommit, preCommit, then doCommit. The extra round is the price for the recovery state that lets participants act on a coordinator crash.
Learn Three-Phase Commit hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
See also
Related glossary terms you might want to look up next.
Two-Phase Commit
A protocol ensuring all nodes in a distributed transaction either commit or abort together. Phase 1: prepare (vote). Phase 2: commit or rollback.
Saga Pattern
A way to manage distributed transactions across microservices using a sequence of local transactions with compensating actions for rollback.
Consensus
The process of getting multiple nodes in a distributed system to agree on a single value. The foundation of distributed databases and coordination services.
CAP Theorem
In a distributed system, you can only guarantee two of three: Consistency, Availability, and Partition tolerance. You must choose your trade-off.
Paxos
A family of protocols for solving consensus in unreliable networks. Famously difficult to understand but mathematically proven correct.
Raft
A consensus algorithm designed to be understandable. Uses leader election and log replication. Powers etcd (used by Kubernetes) and CockroachDB.