---
title: "Kafka ZooKeeper vs KRaft: what freezes leader elections"
description: "Under ZooKeeper, another broker takes over from a lost controller. Losing the ensemble majority freezes Kafka leader elections, as a KRaft quorum loss does."
url: https://monedula.dev/kafka-simulator/scenarios/zk-vs-kraft/
---

# Kafka ZooKeeper vs KRaft: what freezes leader elections

Scenario 06.0.4 · ZooKeeper vs KRaft: the same cluster, two control planes. KRaft · Advanced · about 4 min · Apache Kafka 4.3.

The legacy control plane: an external ZooKeeper ensemble stores metadata, and ONE broker - the one holding its /controller znode - is the controller. Killing the controller broker just lets another claim it; losing the ensemble majority - not a broker - is what freezes leader elections.

Run it: https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4

## What you start with

KRaft makes the controller a quorum of dedicated voters (the other 06.0.x scenarios). Here we run the ZooKeeper plane that Kafka 4.0 removed (Kafka 3.x and earlier): an external 3-node ensemble holds the metadata, and the broker holding its ephemeral /controller znode is the active controller. We kill the controller broker (another broker just claims the znode), then take the ensemble past its majority and watch the same election freeze that a KRaft quorum loss produces.

## Step by step

1. **ZooKeeper control plane - ensemble z0/z1/z2, broker-1 elected controller** (t+0.000s): The control plane is the legacy ZooKeeper plane: an EXTERNAL 3-node ensemble (z0/z1/z2) stores cluster metadata, and ONE broker is the active controller (broker-1 here: the first broker to create the ephemeral /controller znode wins, not necessarily the lowest id). Contrast KRaft, where the controller is a quorum of dedicated voter nodes. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=0)
2. **Two records committed to orders-0 (HW 2), led by broker-1** (t+0.700s): broker-1 is BOTH the partition leader and the ZooKeeper-elected controller. Two records replicate to all three brokers; the high-water mark is 2. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=1)
3. **Controller broker-1 killed → broker-2 takes over /controller; orders-0 election pending** (t+1.300s): Killing the controller BROKER does not kill the control plane - the ensemble is untouched, so the surviving brokers race to recreate /controller and broker-2 wins (a new controller term). broker-1 was also the partition leader, so orders-0 is briefly leaderless while the new controller runs the election. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=2)
4. **New controller broker-2 runs the election → broker-2 leads orders-0** (t+1.800s): The freshly-elected controller broker-2 drives the leader election broker-1's death triggered, electing broker-2 as the new leader. The ensemble survived the broker loss - exactly what makes losing the controller broker non-fatal under ZooKeeper. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=3)
5. **Ensemble node z1 killed → 2 of 3 still a majority, controller unaffected** (t+2.500s): An ensemble of 3 serves while a strict majority (2 of 3) is reachable. Killing z1 leaves z0+z2 - still a majority - so broker-2 keeps the controllership. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=4)
6. **Ensemble node z2 killed → ensemble majority lost → NO controller** (t+2.800s): Now only z0 survives: 1 of 3 is not a majority, so the ensemble stops serving and no broker can hold the /controller znode. The metadata store lives in the ZK NODES, not the brokers - so the control plane fails even though every remaining broker is healthy. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=5)
7. **Partition leader broker-2 killed with no controller → election frozen** (t+3.600s): broker-2 (still the leader) is killed. With no controller to run an election, orders-0 stays leaderless - the election freezes. This is the SAME end state as a KRaft quorum loss (06.0.2), reached through a separate ZooKeeper ensemble. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=6)
8. **Ensemble node z1 restarted → broker-3 becomes controller → frozen election resumes** (t+4.100s): Restoring z1 brings the ensemble majority back (z0+z1). broker-3, the only live broker, claims /controller as the new controller, and the frozen election immediately resumes: broker-3 takes the lead. Recovery comes from restoring the ENSEMBLE, not the brokers. [Open at this step](https://monedula.dev/kafka-simulator/playground/?scenario=06.0.4&t=7)

## The takeaway

Both planes do the same job - store metadata, elect partition leaders - and both freeze elections when their metadata quorum is lost. The difference is WHERE that quorum lives: an external ZooKeeper ensemble (separate nodes) versus KRaft’s dedicated controller voters. Killing the controller broker is survivable in ZooKeeper because the ensemble outlives it; losing the ensemble majority is what actually stops the cluster.

## Further reading

- [Apache Kafka documentation](https://kafka.apache.org/43/operations/kraft/)
