Kafka Bootstrap Servers: How Clients Connect
Kafka bootstrap servers are the host:port addresses a client contacts first to discover a cluster. The client sends one Metadata request to any of them, receives the list of every broker with the address each one advertises, and from then on connects directly to partition leaders. The bootstrap list is an entry point, not the broker list.

What is bootstrap.servers?
bootstrap.servers is a client setting used by producers, consumers, admin clients, Kafka Streams, and Kafka Connect. It contains a comma-separated list of host:port pairs.
Any broker can be a bootstrap server. Every broker holds the full cluster metadata, so the list does not need to include a partition leader or a "primary" node. The list is only used to reach a first broker: once metadata arrives, the client sends data traffic to the addresses the brokers advertise.
# one address is enough to work; two or three survive a broker outage
bootstrap.servers=kafka-1.payments.internal:9092,kafka-2.payments.internal:9092,kafka-3.payments.internal:9092 How Kafka clients connect through bootstrap servers
On its first connection, a client runs these steps:
- Connect to one entry in
bootstrap.servers. Client logs use a negative node id such asnode -1because the broker is not known yet. - Negotiate and authenticate. The TLS handshake completes first when TLS is configured, then the client sends ApiVersions to learn which protocol versions the broker supports, then runs the SASL exchange if SASL is enabled.
- Fetch metadata. The response lists broker addresses and the leader and replicas of each requested partition.
- Connect to leaders. Produce and fetch requests go to the brokers named in the metadata. Consumers also discover their group coordinator. What's really inside Kafka's poll() covers the full consumer startup sequence.

A client can therefore bootstrap fine and still fail at step 4: every address in the metadata must also be reachable from the client network.
Why the bootstrap list is not the broker list
List two or three entries. One entry fails at startup when that broker is down; listing every broker adds nothing after the first connection. Avoid per-broker or vendor-specific hostnames hardcoded in application code: with them, every broker replacement, migration, or provider change means editing every client; hardcoded bootstrap servers are the fastest path to lock-in. Use a DNS name or proxy endpoint the platform team controls, and inject it from configuration rather than compiling it in.
Failure cases:
- A bootstrap broker is down at startup. The client shuffles the list and tries entries until one answers, so the order in the config is not a priority order. Only when no entry answers does it fail with a timeout.
- A bootstrap broker is removed later. Running clients already have metadata and do not notice, but new or restarted clients fail if the list only named that broker. An owned DNS name is repointed once instead of editing every client config.
- All known brokers become unreachable. Since Kafka 4.0,
metadata.recovery.strategydefaults torebootstrap(KIP-1102). A running client returns tobootstrap.serverswhen every broker it knows is unreachable, when no broker returns metadata formetadata.recovery.rebootstrap.trigger.ms(5 minutes by default), or when a broker asks it to rebootstrap. Therebootstrapoption itself was introduced by KIP-899 in Kafka 3.9. - The bootstrap DNS record is repointed during a migration or failover. Running clients stay where they are. They read
bootstrap.serversonly at startup and on rebootstrap; until then they keep using the broker addresses from their last metadata, over open connections that a DNS change does not close. Clients move when they restart or when the old brokers become unreachable and they rebootstrap, which is why DR plans built on a DNS flip also need a way to force reconnections.
A single DNS name can resolve to several broker IPs. With the default client.dns.lookup=use_all_dns_ips, the client tries each returned IP until one connects.
Clients also refresh metadata every metadata.max.age.ms (5 minutes by default) and after any leadership error, from brokers they already know. Picking up leader moves and new partitions does not need the bootstrap list.
listeners vs advertised.listeners
listenersis what the broker binds to: interface and port.PLAINTEXT://0.0.0.0:9092accepts connections on every interface.advertised.listenersis what the broker puts in the metadata response: the address clients and other brokers should use. It must be a real, reachable address, not0.0.0.0.
The classic bug is a broker in Docker or Kubernetes that advertises localhost:9092. A client on the host can connect, but a client in another container or pod receives localhost in the metadata and tries to connect to itself. A positive node id in the error, such as node 1, confirms that bootstrap worked and the advertised address failed. Advertise a name the client can resolve and reach:
# broker: bind everywhere, advertise the name clients will use
listeners=PLAINTEXT://0.0.0.0:9092
advertised.listeners=PLAINTEXT://kafka-1.payments.internal:9092 A broker that serves both other containers and the Docker host needs two listeners. The Compose service name does not resolve on the host, and localhost inside a container is the container itself. The settings are explained in the next section:
# single-node KRaft broker in Docker Compose, service "kafka", port 29092 published to the host
listeners=INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:29092,CONTROLLER://0.0.0.0:9093
advertised.listeners=INTERNAL://kafka:9092,EXTERNAL://localhost:29092
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT
inter.broker.listener.name=INTERNAL
controller.listener.names=CONTROLLER Containers use bootstrap.servers=kafka:9092; applications on the host use bootstrap.servers=localhost:29092.
For a step-by-step walkthrough of this setting on Docker and cloud hosts, see Kafka advertised host setting.
Multiple listeners and security protocols
To serve other brokers on a private interface, applications inside the VPC, and clients outside it, a broker declares several named listeners. Each has its own port, advertised address, and security protocol.
listeners=INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9093
advertised.listeners=INTERNAL://kafka-1.payments.internal:9092,EXTERNAL://kafka-1.payments.example.com:9093
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:SASL_SSL,CONTROLLER:PLAINTEXT
inter.broker.listener.name=INTERNAL
controller.listener.names=CONTROLLER listener.security.protocol.map maps each listener name to a protocol such as PLAINTEXT or SASL_SSL. inter.broker.listener.name selects the listener used between brokers. controller.listener.names names the listener used to reach the KRaft controllers. On a KRaft broker, every name in controller.listener.names must also appear in listener.security.protocol.map once that map is set explicitly; otherwise the broker refuses to start with Controller listener with name CONTROLLER defined in controller.listener.names not found in listener.security.protocol.map.
A client receives addresses for the listener it used during bootstrap. A client connecting on port 9093 gets the EXTERNAL hostnames; a client on 9092 gets the INTERNAL ones. Each network only sees addresses it can reach. See Kafka authentication and mTLS for Kafka for the security settings.
Kafka behind a load balancer, NAT, or proxy
A route between two networks (VPC peering, a transit gateway) is not the same as Kafka reachability. The client must resolve and reach every advertised broker address from where it sits, so connecting Kafka across networks is an addressing problem, not a routing one. A load balancer can provide a stable bootstrap address because any broker can answer the metadata request, but a single TCP load balancer cannot carry the traffic after that: internal advertised addresses are unreachable from outside, and one shared advertised address sends connections to random brokers.
Three setups give each client a path to a specific broker:
- One routable address per broker. Each broker advertises its own external hostname, backed by a load balancer or NAT rule. Each broker then needs its own DNS record, certificate name, and load balancer or NAT entry. On KRaft clusters
advertised.listenersis a static setting, so every address change means a rolling restart. Managed services often do not let users changeadvertised.listeners; this MSK cross-VPC guide covers that case. - SNI routing. All brokers share one address and one TLS port. Each broker is advertised under a distinct hostname (
b1.kafka.example.com,b2.kafka.example.com). The client puts that hostname in the TLS ClientHello (Server Name Indication), and a TLS-passthrough router in front sends the connection to the right broker without decrypting it. This needs TLS on that listener and a certificate that covers every broker name. SNI is a routing hint sent in cleartext, not authentication: SASL or mTLS still decides who may connect. - A Kafka-protocol proxy. The proxy rewrites broker addresses in Metadata and FindCoordinator responses, mapping each internal broker to a client-facing address. Conduktor Gateway supports one port per broker or one hostname per broker with SNI routing; see Kafka proxies compared.

KRaft: bootstrap.servers vs bootstrap.controllers
In KRaft mode, controllers keep cluster metadata but do not serve producers or consumers. Regular clients must use broker listeners in bootstrap.servers; a controller listener returns The node does not support METADATA.
Admin tools can use --bootstrap-controller (config key bootstrap.controllers) for a small set of controller operations, such as describing the quorum:
kafka-metadata-quorum.sh --bootstrap-controller localhost:9093 describe --status
# (excerpt)
# LeaderId: 1
# CurrentVoters: [{"id": 1, "endpoints": ["CONTROLLER://localhost:9093"]}] Do not set bootstrap.servers and bootstrap.controllers on the same admin client. See KRaft mode for the controller architecture.
Troubleshooting connection errors
The Java client logs most network problems as the same Connection to node ... warning. Read the node id (negative = bootstrap, positive = advertised address) and the address in it. Messages below were captured on Apache Kafka 4.3.1 unless marked otherwise.
| Message | Stage | Likely cause |
|---|---|---|
Couldn't resolve server ... from bootstrap.servers as DNS resolution failed for , then No resolvable bootstrap urls given in bootstrap.servers | Client startup | No hostname in bootstrap.servers resolves: a typo, or a Docker service name used from the host. The client fails before any connection attempt. |
Connection to node -1 (host/ip:port) could not be established. Node may not be available. | Bootstrap (negative node id) | Wrong host or port in bootstrap.servers, broker down, firewall, or connection refused. Nothing Kafka-specific yet. |
Connection to node 1 (localhost/127.0.0.1:9092) could not be established. after a successful start | After bootstrap (real broker id) | advertised.listeners names an address the client cannot reach: localhost, a Docker service name, a private IP. |
Timed out waiting for a node assignment. / Expiring N record(s) for orders-0 | After bootstrap | Same cause as above; the admin or producer request never reached the leader. |
Bootstrap broker kafka-1:9093 (id: -1 rack: null isFenced: false) disconnected | Bootstrap | The port accepts the TCP connection but closes it instead of answering: PLAINTEXT client on an SSL or SASL listener, or a non-Kafka service on that port. |
The node does not support METADATA | Bootstrap | The address is a KRaft controller listener, not a broker listener. |
SSLHandshakeException ... No subject alternative DNS name matching ... (JVM message, not reproduced) | Any TLS connection | The advertised hostname is not in the broker certificate's SANs; frequent with SNI routing or per-broker external names. |
NOT_LEADER_OR_FOLLOWER on most produce and fetch requests (not reproduced) | After bootstrap | All advertised addresses point at one shared load balancer address; connections land on arbitrary brokers. |
What is a bootstrap server in Kafka?
A bootstrap server is any broker address a client uses to make its first connection and fetch cluster metadata. Any broker can play this role, since every broker knows the full cluster layout. After that first exchange the client connects directly to partition leaders using the addresses brokers advertise.
Is the bootstrap server the same as a broker?
A bootstrap server is a broker, but the bootstrap list is not the broker list. The client only uses bootstrap.servers to find one live broker; the actual set of brokers, and the addresses used for produce and fetch traffic, come from the metadata response and from each broker's advertised.listeners.
How many bootstrap servers should I list?
Two or three. One is enough for the handshake, but the client cannot start if that broker is down. Listing every broker adds nothing after the first connection and makes client configs churn each time a broker is replaced. A DNS name resolving to several brokers works as a single entry.
Why does my client connect on localhost but time out from Docker or Kubernetes?
The broker advertises localhost:9092 in its metadata. Clients on the same host can reach that; clients in another container or pod cannot. The client log shows "Connection to node 1 (localhost/127.0.0.1:9092) could not be established". Set advertised.listeners to a hostname every client can resolve.
Can I put a load balancer in front of Kafka?
Not a plain TCP load balancer on its own. Clients must reach specific brokers after bootstrap, so a single shared address either exposes unreachable internal names or sends requests to the wrong leader. Use one address per broker, SNI routing over TLS, or a Kafka-protocol proxy that rewrites the addresses in the metadata response.
What is the difference between --bootstrap-server and --bootstrap-controller?
--bootstrap-server targets broker listeners and is what producers, consumers and most admin commands use. --bootstrap-controller (Kafka 3.7+, KIP-919) targets the KRaft controller quorum for a small set of admin operations, such as describing the quorum, and is meant for diagnostics when brokers are unavailable.
Related Pages
- Kafka Brokers Explained: what the servers behind the bootstrap list do.
- Kafka Cluster: how brokers form the cluster whose metadata the bootstrap request returns.
- Kafka Partitions Explained: why clients need the leader of each partition, not just any broker.
- Understanding KRaft Mode in Kafka: the controller quorum that
bootstrap.controllerstargets. - Kafka Authentication: SASL, SSL, OAuth: the security protocols assigned per listener.
- Kafka Architecture Diagram: the full picture of producers, consumers, brokers and controllers.
- What's Really Inside Kafka's poll()?: the consumer's connections after bootstrap, coordinator lookup and sticky connections.
- Connect Kafka Across VPCs Without Extra Peering: why cross-network Kafka is an addressing problem, not a routing one.
Sources and References
- Apache Kafka 4.3 producer configs: bootstrap.servers, client.dns.lookup, metadata.max.age.ms, metadata.recovery.strategy
- Apache Kafka 4.3 broker configs: listeners, advertised.listeners, listener.security.protocol.map, inter.broker.listener.name, controller.listener.names
- A Guide to the Kafka Protocol: partitioning and bootstrapping, ApiVersions, Metadata
- KIP-919: Allow AdminClient to Talk Directly with the KRaft Controller Quorum
- KIP-1102: Enable clients to rebootstrap based on timeout or error code
- KIP-899: Allow producer and consumer clients to rebootstrap
- KIP-602: Change default value for client.dns.lookup
- Kafka Listeners Explained (Robin Moffatt, Confluent)