Two-phase commit

Also known as: 2PC

On this page 8

Two-phase commit (2PC) is an atomic commitment protocol that ensures all participants in a distributed transaction either all commit or all abort. In databases, it extends the atomicity of ACID transactions across several resource managers, such as two database servers or a database and a message broker, using a coordinator that collects votes in a prepare phase and announces the outcome in a commit phase.

2PC guarantees agreement on the outcome but not availability: if the coordinator fails at the wrong moment, participants can be blocked while holding locks. This trade-off explains both its long use in enterprise systems and the search for alternatives in large distributed architectures.

How the two phases work

The protocol separates the decision from its execution. In the first phase, the coordinator asks every participant whether it can commit; in the second phase, it tells all participants the single global decision. Each participant must write its state to a durable log before answering, so that it can keep its promise even after a crash.

  1. Prepare request: the coordinator sends a prepare message to every participant.
  2. Vote: each participant makes its changes durable, keeps its locks, force-writes a prepared record to its write-ahead log and replies yes, or replies no and rolls back.
  3. Decision: if all votes are yes, the coordinator force-writes a commit record; any no vote or timeout leads to abort.
  4. Outcome: the coordinator sends commit or rollback to all participants.
  5. Acknowledgment: participants apply the outcome, release locks and acknowledge, after which the coordinator can forget the transaction.

The moment a participant votes yes, it enters the in-doubt state: it has given up the right to abort on its own and must wait for the coordinator. This loss of autonomy is the price of guaranteed atomicity.

Participant states and failure handling

Correct recovery depends on knowing which state each node reached before a failure. The durable log records make this possible, and recovery logic acts according to the last logged state.

State at failureWho failedRecovery action
Before votingParticipantCoordinator times out and aborts
Prepared, in doubtParticipantOn restart, asks the coordinator for the outcome
Prepared, in doubtCoordinatorParticipants block, locks held until coordinator returns
Decision loggedCoordinatorOn restart, resends the decision to all participants
Committed locallyParticipantRedo from the log, then acknowledge
What happens when a failure occurs in each state

The blocking case is the central weakness of 2PC. While participants wait in doubt, their locked rows are unavailable to other transactions. Operators can resolve such transactions manually with a heuristic decision, but if that guess differs from the coordinator’s real decision, the result is a heuristic hazard: data that is no longer atomic across systems.

Implementations and standards

Most production use of 2PC follows the X/Open XA specification, which defines the interface between a transaction manager and resource managers. Application servers expose it through APIs such as the Java Transaction API, while databases offer explicit prepare and commit commands for external coordinators.

System2PC mechanismNotes
PostgreSQLPREPARE TRANSACTION and COMMIT PREPAREDDisabled until max_prepared_transactions is raised above 0
MySQLXA START, XA PREPARE, XA COMMITAlso used internally between the binary log and InnoDB
SQL ServerDistributed transactions through a coordinator serviceCommon with linked servers
Java platformsJTA with XA-capable driversSpans databases and message queues
Distributed SQL databases2PC across shards with replicated coordinatorsConsensus keeps the coordinator available
Where two-phase commit appears in practice

Optimizations and variants

Basic 2PC needs two message round trips and several forced log writes per transaction, so implementations use optimizations that reduce messages and disk flushes without weakening atomicity.

  • Presumed abort: the coordinator does not log aborts; missing information means abort, which saves writes for failed transactions.
  • Presumed commit: the inverse optimization, reducing cost for the common successful case.
  • Read-only optimization: a participant that changed nothing votes read-only and skips the second phase.
  • One-phase commit: with a single participant, the coordinator skips the prepare phase entirely.
  • Last resource commit: one non-XA resource is committed last, with its result acting as the decision.

Three-phase commit (3PC) adds a pre-commit phase to avoid blocking, but it is only safe under assumptions of bounded delays and no network partitions, so it is rarely used. Modern systems instead replicate the coordinator with a consensus protocol such as Paxos or Raft, which removes the single point of blocking.

Two-phase commit compared with alternatives

2PC provides strong atomicity at the cost of latency and availability. Architectures that cannot accept blocking or cross-service locks use patterns that give up immediate atomicity in exchange for independence.

ApproachConsistencyMain trade-off
Two-phase commitAtomic, immediateBlocking and held locks on coordinator failure
Three-phase commitAtomic under strict timing assumptionsUnsafe with network partitions
Consensus-replicated 2PCAtomic, highly availableMore replicas and complexity
SagaEventual, with compensating actionsIntermediate states visible to others
Transactional outboxEventual between database and messagesRequires idempotent consumers
2PC and alternative coordination approaches

Microservice architectures usually avoid 2PC because it couples service availability and requires every service to support XA. Within a single distributed database, however, 2PC remains the standard way to commit transactions that span shards.

Operational pitfalls

The most common operational problem is the orphaned prepared transaction: a participant left in the prepared state after a coordinator was lost or misconfigured. It keeps locks indefinitely and, in PostgreSQL, also prevents VACUUM from removing old row versions. Monitoring views of prepared transactions and alerting on their age are essential wherever 2PC is enabled.

The simple explanation

Two-phase commit works like a wedding ceremony. The officiant first asks each partner whether they agree. Only when both say yes does the officiant declare the marriage. If either says no, nothing happens at all.

Once a partner has said yes, they cannot walk away and must wait for the declaration. That is the weak spot: if the officiant disappears at that moment, everyone is stuck waiting. Computers use the same idea to make sure changes in several systems succeed together or not at all.

How it is used in practice

A bank runs its account ledger in one database and its payment message queue in another system. When a customer sends a transfer, the ledger must be debited and the outgoing payment message must be queued, and neither may happen without the other.

The bank’s transaction manager coordinates both resources with XA two-phase commit. Both resources prepare, log their state and vote yes; only then does the coordinator log the commit decision and tell both to commit. When a server crashes after the prepare phase, recovery asks the coordinator for the outcome and completes the transfer.

The result is that customers never see money debited without a payment sent. The operations team monitors in-doubt transactions and keeps the coordinator on redundant infrastructure to limit the time locks can be held.