Raft Leader Leases and Linearizable Reads
For a leader to answer reads from local state without contacting a quorum every time, it needs a time-based lease. This post covers the conditions that make a lease valid, the paths along which it silently breaks, the log-based lease LeaseGuard proposes, and the availability price paid right after a leader change.
A lease removes the round trip from the read path by moving the grounds for correctness from the log to the clock, and the price shows up as availability at the moment the leader changes.
The round trip on every read
Raft guarantees write linearizability through log replication, but reads do not inherit that guarantee without an additional mechanism. A former leader that has already been demoted to follower while still believing it is the leader is called a stale leader. If that node answers from its local state, the client receives a value that does not reflect writes the new leader has already committed.
The standard remedy is a quorum check: on every read, the leader confirms with a quorum that it is still the valid leader. Raft implementations usually expose this under the name ReadIndex. It is correct, but it adds one network round trip to every single read.
The cost does not stop at one round trip. The LeaseGuard paper by Davis, Demirbas, and Deng (arXiv:2512.15659, SIGMOD 2026) measured it directly. The subject was LogCabin, the reference implementation of Raft. With network delay at 10ms, read latency under quorum reads stretched to 16 seconds because of queueing effects. Round-trip delay caused requests to pile up, and the backlog in turn amplified the delay.
| Read method | Extra round trip | Consistency | Price |
|---|---|---|---|
Quorum read (ReadIndex) | 1 RTT | Linearizable | Latency, I/O contention, cloud network cost |
| Follower stale read | None | Eventual only | Stale values must be acceptable |
| Leader lease read | None | Linearizable | Depends on clock accuracy, availability after a change |
The third row is the subject of this post. It keeps the leader-based structure intact and drives the read path to zero round trips, and this post traces where that cost moves instead.
What makes a lease valid
A leader lease skips the quorum check on the grounds of time. It reduces to a single invariant. At any given instant, no two nodes may both believe they are the leader and answer reads.
The leader serves reads locally only after securing an interval in which no other leader can be elected for the next Δ. The original form proposed by Ongaro in 2014 treats the leader as holding a lease from the moment a quorum of RPCs succeeds within the election timeout. That definition is where the trouble starts later.
The value chosen for the lease duration Δ is tied to the election timeout (ET). If Δ is shorter than ET, the lease breaks often and the window for local reads shrinks. If Δ is longer than ET, a new leader spends more time waiting without a lease. LeaseGuard recommends aligning the two at Δ = ET.
Expiry is not decided against a single point in time. Each node assumes a bounded-uncertainty clock that works with interval timestamps of the form [earliest, latest]. If the recorded time of an entry is e, the lease is definitely expired only when e.latest + Δ is smaller than the earliest of the current time. In an environment where the error bound is unknown, that comparison does not hold at all.
Where leases break
A lease does not fail loudly. While the valid intervals of two leaders briefly overlap, a stale value simply goes out looking like a normal response.
The first path is clock error between nodes. What follows is what happens when a node whose clock runs fast by e declares the lease expired first.
Lease of leader A [T0, T0+Δ] (by A's clock)
Clock of node B runs ahead of A by e
B: declares expiry at T0+Δ-e -> starts an election -> becomes the new leader
A: believes it is the leader until T0+Δ and answers reads locally
During the overlapping interval e, two leaders serve reads at onceThe second path is message delay. If the lease start is anchored only on the time the quorum responses arrive, the delay between sending the request and receiving the response falls outside the lease interval. HashiCorp Raft still omits this term, and the consistency violation reported in 2016 remains unfixed as of 2025.
The third path has nothing to do with clocks. If a GC pause or scheduling delay lands between the lease validity check and the actual response, the node answers on the grounds of a lease that has already expired. Whenever the lease time remaining at the moment of the check is shorter than the pause, the invariant is violated outright.
| System | Lease approach | Known problem |
|---|---|---|
| HashiCorp Raft | Leader lease | Expiry calculation ignores message delay. Reported in 2016, unfixed as of 2025 |
| etcd | Leader lease | Lease timeout miscalculation allows stale reads. Reported in 2024 |
| TiDB | Lease managed by the Placement Driver | Requires separate infrastructure, and a 10-second lease leaves 10 seconds of unavailability after an election |
| CockroachDB | Lease per data range | Lease acquisition is an extra coordination step, with a delay inserted for the maximum clock offset (500ms by default) |
| YugabyteDB | Allows lease overlap during an election | Candidates must explicitly learn the previous lease information |
| MongoDB | No lease | Works around it by replicating an empty log entry per read, at the same communication cost as a quorum check |
The LeaseGuard paper identifies the common cause as an ambiguous specification. The original description of leases was prose only, with no formal specification. Each implementation therefore interpreted expiry computation and lease handover during a leader change differently.
The log is the lease
LeaseGuard adds no lease-specific message and no lease-specific data structure. It grounds the lease in a property Raft already guarantees, Leader Completeness. That property states that a newly elected leader holds every earlier log entry a quorum replicated.
The leader records an interval timestamp alongside each log entry. If the timestamp of the last committed entry falls within Δ, the fact that the entry was replicated to a quorum is itself the proof that no other leader can exist. Followers learn the lease state from ordinary log replication, so no extra communication is involved.
The premise of this design is still the clock. The paper's measurements ran in an environment where AWS TimeSync and PTP held the error bound under 50µs on average. CockroachDB inserting a delay equal to the maximum clock offset on non-cooperative lease acquisition addresses the same problem by a different route.
The verification method differs as well. LeaseGuard specifies the protocol formally in TLA+ and checks correctness theorems along with it. Those theorems include Read-Your-Writes, which states that every read observes the effect of preceding writes. Read At Highest commitIndex, which states that a read reflects the newest state of the replica set, is included too.
The gap right after a leader change
Lease-based reads cost little during steady state. The cost shows up at the moment the leader changes. A new leader is safe only after waiting for the old leader's lease to expire, and if it can do nothing during that window, writes and reads stop together. TiDB going unavailable for 10 seconds after an election is the extreme case of this gap.
LeaseGuard fills the gap in two ways. Deferred Commit Writes lets the new leader accept writes even while waiting and replicate them to followers. Only the commitIndex update is deferred until the old leader's last entry passes Δ. The moment the lease opens, the commit can be confirmed immediately with no additional communication.
Inherited Lease Reads let the new leader inherit the old leader's lease and serve reads at once, provided the old leader's last committed entry has not yet passed Δ. Entries above the commitIndex at election time and below the election index form the limbo region. For those, the new leader cannot know how far the old leader committed. For keys caught in that range, safety comes from reading several versions under multi-version concurrency control (MVCC) and comparing them.
Both optimizations came out of exploring the TLA+ specification. The paper describes the limbo region problem as something the formal specification itself surfaced, which makes the specification a design tool rather than an after-the-fact check.
The measurements ran on three AWS EC2 m7g.xlarge nodes (us-east-1, average ping 155µs), with about 1,600 lines modified out of roughly 27,000 in LogCabin.
| Metric | Quorum check | Ongaro 2014 lease | LeaseGuard |
|---|---|---|---|
| Extra round trip per consistent read | 1 RTT | None | None |
| Write throughput right after a change | - | Drops sharply | About 1,000 → about 10,000 writes/sec |
| Read availability right after a change | - | 0% until the lease expires | About 99% |
| Staying under 100ms with a 50% write mix | Latency spikes at 5,000 ops/sec | Latency rises around 25,000 ops/sec | Held up to 25,000 ops/sec |
How much availability comes back depends on the workload. Experiments shifted the read distribution to Zipfian. A uniform distribution (a=0) succeeded at 3,000 reads per second, while a distribution concentrated on a few keys (a=2) dropped below 500 per second. The more reads converge on keys caught in the limbo region, the less the inherited lease helps.
How far to extend the lease
The first criterion is the clock infrastructure. In an environment where the error bound cannot be measured, using a quorum check instead of a lease is the correct call. Turning on a lease without knowing the bound means violations go undetected when they occur.
The second is the shape of the workload. The higher the read share, the more the removed round trip is worth. A write-heavy workload gains less, because the quorum check accounts for a smaller portion of the total cost. On top of that, consider whether a read gap of Δ right after a leader change is acceptable.
Whether the lease goes to a single leader is also a choice. Moraru, Andersen, and Kaminsky distributed the lease across a quorum of nodes with Quorum Leases at ACM SoCC 2014. Any node holding a lease can serve linearizable reads locally, but a write has to be confirmed by every node holding a lease on that data. If one of them is slow, the whole write is slowed by that much.
Bodega generalizes the lease target to an arbitrarily designated set of responders. Hu, Arpaci-Dusseau, and Arpaci-Dusseau published the design on arXiv in September 2025 (arXiv:2509.07158). Cluster metadata called the roster tracks both who the leader is and which nodes serve local reads. The mechanism that maintains consensus on that roster is the roster lease. From this angle, a leader lease is the special case where the lease-holding set is fixed at one node.
| Lease-holding set | Representative case | Where local reads happen | Price |
|---|---|---|---|
| One leader | Raft leader lease, sofa-jraft LeaseRead | The leader only | Simple to implement, but distant clients still go remote |
| Fixed quorum set | Paxos Quorum Leases (SoCC 2014) | At every lease-holding node | Writes require confirmation from every lease holder |
| Arbitrary responder set | Bodega roster lease (2025) | At any designated responder | Roster reconfiguration becomes a new consensus target |
What shows up in practice is usually the first row. As with sofa-jraft offering ReadIndex and LeaseRead side by side, many implementations keep quorum checks and lease reads as options and let the operator pick. Moving down the rows brings reads closer, at the cost of a heavier write path and heavier reconfiguration logic.
Summary
A leader lease removes one round trip from the read path and, in exchange, moves the grounds for correctness from the log to the clock. It therefore must not be turned on where the error bound is unknown, and even with accurate clocks it can break silently through message delay or a process pause. LeaseGuard removed that ambiguity by defining the lease as the timestamp on a log entry rather than a separate data structure. Those two optimizations raised write throughput after a leader change from about 1,000 to about 10,000 writes/sec, and read availability from 0% to about 99%. Decide on adoption by whether the clock error bound is known, how large the read share is, and whether the short read gap right after a change is tolerable.