Kafka operators frequently encounter configuration issues that manifest as performance degradation, data loss, or cluster instability. These problems often stem from misunderstood defaults, version-specific behavior changes, or settings that work in development but fail under production load. This article provides a structured approach to identifying, validating, and correcting common Kafka configuration mistakes with version-aware commands, observable verification steps, and tested recovery paths. The focus remains on broker and client configuration for Kafka 3.x and 4.x deployments running on Linux, with ZooKeeper or KRaft mode. ## Version and Environment Inventory Before making any configuration change, establish a precise baseline of the running environment. Kafka behavior varies significantly between versions — for example, KRaft metadata quorum replaced ZooKeeper as the default in Kafka 3.3 and became production-ready in 3.5. Controller listener configuration, quota enforcement, and log cleanup semantics all shifted across these releases. Start by capturing the installed version and deployment topology using read-only commands: # On each broker, verify the Kafka version and Scala suffix kafka-broker-api-versions --bootstrap-server localhost:9092 | head -5 # Check process arguments to confirm mode (KRaft vs ZooKeeper) ps aux | grep -E 'kafka\.Kafka|org\.apache\.kafka\.server\.KafkaMetadataServer' # Inspect listener configuration currently in effect kafka-configs --bootstrap-server localhost:9092 --entity-type brokers --entity-name 1 --describe Record the output with timestamps. Note the listener map (PLAINTEXT, SSL, SASL_SSL), advertised listeners, and whether controller.listener.names or controller.quorum.voters is configured. Identify the log directory layout ( log.dirs or metadata.log.dir for KRaft) and confirm disk layout with lsblk -f and df -h /var/lib/kafka . Prerequisites for safe changes: - Root or kafka user access to all brokers - Maintenance window with partition leadership migration capability - Backup of current server.properties on each node - Monitoring dashboards showing under-replicated partitions, request latency, and controller elections The smallest justified change is a single property modification on one broker, verified before rolling to others. Never modify multiple unrelated settings simultaneously. ## Safe Configuration Path Configuration changes must follow an observe-plan-verify-rollback cycle. The following sections address the most frequent mistake categories with concrete examples. ### Listener and Advertised Listener Misconfiguration A common error is setting listeners=PLAINTEXT://0.0.0.0:9092 but omitting or misconfiguring advertised.listeners . Clients then receive the container-internal hostname or localhost , causing connection timeouts from external producers and consumers. Observation: Capture current listener state: kafka-configs --bootstrap-server localhost:9092 --entity-type brokers --entity-name 1 --describe | grep -E 'listeners|advertised.listeners' Expected result: advertised.listeners shows reachable host:port for each security protocol (e.g., PLAINTEXT://kafka-1.prod.example.com:9092,SSL://kafka-1.prod.example.com:9093 ). Failure signal: Producer logs show Connection to node -1 (localhost/127.0.0.1:9092) could not be established or bootstrap broker disconnected . Change: On one broker, update server.properties : listeners=PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9093 advertised.listeners=PLAINTEXT://kafka-1.prod.example.com:9092,SSL://kafka-1.prod.example.com:9093 listener.security.protocol.map=PLAINTEXT:PLAINTEXT,SSL:SSL inter.broker.listener.name=PLAINTEXT Verification: Restart the broker. Confirm client connectivity: kafka-producer-perf-test --topic test-connectivity --num-records 10 --record-size 1000 --throughput 10 --producer-props bootstrap.servers=kafka-1.prod.example.com:9092 Expect "10 records sent" with no connection errors. Rollback: Restore original server.properties and restart. Verify leadership returns to preferred replicas with kafka-leader-election --bootstrap-server localhost:9092 --election-type PREFERRED --all-topic-partitions . ### Log Retention and Compaction Defaults Default log.retention.hours=168 (7 days) and log.retention.bytes=-1 (unlimited) often conflict with capacity planning. Teams discover disk pressure only after alerts fire. Compaction settings ( min.cleanable.dirty.ratio=0.5 , min.compaction.lag.ms=0 ) may retain tombstones longer than expected, bloating segments. Observation: Check current log config per topic: kafka-configs --bootstrap-server localhost:9092 --entity-type topics --entity-name orders --describe kafka-log-dirs --bootstrap-server localhost:9092 --describe --topic-list orders Expected result: Retention aligns with SLA (e.g., retention.ms=259200000 for 3 days). Compaction lag shows min.compaction.lag.ms=3600000 (1 hour) for event-sourced topics. Failure signal: Disk usage >80% on log volumes; kafka-log-dirs shows segments older than retention window; consumer lag spikes during log cleaning. Change: Apply topic-level override (safer than broker-wide): kafka-configs --bootstrap-server localhost:9092 --entity-type topics --entity-name orders --alter --add-config retention.ms=259200000,min.compaction.lag.ms=3600000,cleanup.policy=compact,delete Verification: After 24 hours, re-run kafka-log-dirs --describe and confirm segment count and size decreased. Monitor kafka.server:type=LogManager,name=LogCleanerTimeMsPerInterval metric. Rollback: Revert to previous config with --delete-config retention.ms,min.compaction.lag.ms . ### Replication Factor and Min In-Sync Replicas Mismatch Creating topics with replication.factor=3 but leaving min.insync.replicas=1 (default) allows writes to succeed with only one replica acknowledged. If two brokers fail, data loss occurs despite apparent replication. Observation: For each critical topic: kafka-topics --bootstrap-server localhost:9092 --topic payments --describe kafka-configs --bootstrap-server localhost:9092 --entity-type topics --entity-name payments --describe | grep min.insync.replicas Expected result: min.insync.replicas=2 when replication.factor=3 . Producer config uses acks=all . Failure signal: Under-replicated partitions persist after broker restart; UncleanLeaderElectionEnable metric increments. Change: Update topic config: kafka-configs --bootstrap-server localhost:9092 --entity-type topics --entity-name payments --alter --add-config min.insync.replicas=2 Verification: Produce with acks=all and confirm kafka-producer-perf-test reports zero errors. Induce a broker stop and verify ISR shrinks but writes continue. Rollback: Restore min.insync.replicas=1 if throughput impact is unacceptable, but document the durability trade-off. ### Quota and Throttling Blind Spots Unbounded producer/consumer throughput can saturate network or disk, causing cascading latency. Default quota.producer.default and quota.consumer.default are unlimited. Observation: Check current quotas: kafka-configs --bootstrap-server localhost:9092 --entity-type clients --entity-name '*' --describe --entity-default Expected result: Byte-rate quotas set per client-id or principal (e.g., producer_byte_rate=10485760 for 10 MB/s). Failure signal: RequestExceededQuota metric spikes; broker network-processor threads at 100%; consumer fetch latency >500ms. Change: Apply default quota, then per-client overrides: kafka-configs --bootstrap-server localhost:9092 --alter --entity-type clients --entity-default --add-config producer_byte_rate=10485760,consumer_byte_rate=20971520 kafka-configs --bootstrap-server localhost:9092 --alter --entity-type clients --entity-name etl-pipeline --add-config producer_byte_rate=52428800 Verification: Run load test; confirm QuotaExceeded metric remains zero. Monitor kafka.network:type=SocketServer,name=NetworkProcessorAvgIdlePercent >20%. Rollback: Remove quota configs with --delete-config . ## Verification and Diagnostics After any change, verify using multiple independent signals. Do not rely on a single metric. ### Broker Health Verification # Confirm controller stability (KRaft) kafka-metadata-quorum --bootstrap-server localhost:9092 describe --status # Check partition leadership distribution kafka-topics --bootstrap-server localhost:9092 --describe --topic payments | grep -c Leader # Validate log cleaner progress kafka-log-dirs --bootstrap-server localhost:9092 --describe --topic-list payments | jq '.brokers[0].logDirs[0].partitions[] | select(.size > 100000000)' ### Client-Side Validation Producers and consumers must reflect broker config changes. Verify producer acks=all and enable.idempotence=true : kafka-producer-perf-test --topic payments --num-records 1000 --record-size 1000 --throughput 1000 --producer-props bootstrap.servers=kafka-1.prod.example.com:9092 acks=all enable.idempotence=true Expect zero RecordError and OutOfOrderSequence metrics. Consumer group lag should stabilize: kafka-consumer-groups --bootstrap-server localhost:9092 --group payment-processor --describe Lag per partition should trend downward and remain <1000 under steady load. ### Configuration Drift Detection Automate daily comparison of running config vs. version-controlled server.properties : # On each broker kafka-configs --bootstrap-server localhost:9092 --entity-type brokers --entity-name 1 --describe > /tmp/running-config-$(hostname).txt diff -u /etc/kafka/server.properties /tmp/running-config-$(hostname).txt || alert "Config drift detected on $(hostname)" ## Failure Modes and Recovery ### Scenario: Rolling Restart Causes Controller Election Storm Symptoms: Frequent controller elections ( ControllerChangeRate >5/min), metadata fetch timeouts, producer NotControllerException . Root cause: Modifying controller.quorum.voters or controller.listener.names on multiple brokers simultaneously without quorum stability. Recovery: - Stop all but three brokers (minimum quorum). - Verify metadata quorum health: kafka-metadata-quorum --bootstrap-server :9092 describe --status - Restart remaining brokers one at a time, waiting for ActiveControllerCount=1 on each before proceeding. - Re-enable client traffic after UnderReplicatedPartitions=0 for 5 minutes. ### Scenario: Log Directory Corruption After Disk Failure Symptoms: Broker fails to start with CorruptRecordException or OffsetOutOfRangeException . Recovery: - Isolate broker: remove from advertised.listeners in other brokers' config, reload. - Replace disk, mount at same path. - Restore from latest backup of __consumer_offsets and transaction state topics if available. - If no backup, delete affected topic partitions and recreate — accept data loss for non-critical topics. - Re-add broker to cluster, trigger preferred replica election. ### Scenario: Quota Misconfiguration Blocks Critical Pipeline Symptoms: QuotaViolationException in producer logs; business-critical topic stalls. Recovery: - Immediately increase quota for affected client-id: kafka-configs --bootstrap-server localhost:9092 --alter --entity-type clients --entity-name critical-etl --add-config producer_byte_rate=104857600 - Verify within 30 seconds: kafka-producer-perf-test succeeds. - Post-incident: review quota hierarchy (default ## Operations Checklist Use this checklist before and after any Kafka configuration change: Pre-change: - [ ] Current server.properties backed up on all brokers - [ ] Version and deployment mode (KRaft/ZooKeeper) documented - [ ] Maintenance window approved; stakeholders notified - [ ] Single property change scoped to one broker first - [ ] Verification commands prepared and tested in staging - [ ] Rollback procedure documented with exact commands - [ ] Monitoring dashboards open: under-replicated partitions, controller elections, request latency, disk usage During change: - [ ] Apply change to one broker; restart only that broker - [ ] Wait 2 minutes for metadata propagation - [ ] Run verification commands; compare to expected signals - [ ] Confirm no new alerts in monitoring - [ ] Proceed to next broker only if verification passes Post-change: - [ ] Run full cluster verification (all brokers, critical topics) - [ ] Validate producer/consumer metrics for 30 minutes - [ ] Update version-controlled config repository - [ ] Record change in operations log with timestamp, author, verification results - [ ] Schedule follow-up review in 7 days for latent issues ## Conclusion Kafka configuration mistakes with practical examples become useful only when each recommendation is version-scoped, observable, and reversible where the technology permits. Copying a command without checking prerequisites and expected output is not an operations procedure. The patterns in this article — listener misalignment, retention defaults, replication quorum gaps, and unbounded quotas — represent the majority of production incidents traced to configuration. By following the observe-plan-verify-rollback cycle, capturing baselines before changes, and automating drift detection, teams reduce mean time to detection and eliminate entire classes of preventable outages. As a next step, choose one low-risk verification from this guide, record the current state, run the documented check, compare the result with the expected signal, and extend the checklist to cover your specific topic designs and client configurations.