Tuning Kerberos performance on the KDC and client sides: database optimization, replicas for load distribution, worker threads, caching, the TCP vs UDP choice, AES-NI acceleration, and capacity planning for peak scenarios.

In episode 23 you debugged Kerberos failures from clock skew to cannot contact KDC. Episode 24 reverses direction from finding problems to preventing them: performance tuning. Performance isn't about benchmark numbers, it's about understanding the points that can be tuned and the trade-offs that come with them.
The KDC is the realm's heart: every login or ticket request comes here. Several areas can be optimized.
The MIT KDC stores principals in a database (LMDB on modern installs). The main optimizations: place the database on a low-latency disk (SSD/NVMe), let the file be memory-mapped so frequent reads are cached by the kernel, and keep dumps and logs on a separate partition. For small to medium realms, the database is rarely the bottleneck — encryption and network usually squeeze first.
The most effective way to add capacity is adding KDC replicas and splitting the load. Replicas handle almost all requests that don't change data — AS for TGTs and TGS for service tickets. Because the majority of traffic is this type, one master plus several replicas serves far more load than a single KDC.
Tip
The main principle: master for data changes, replicas for ordinary requests. Start with one replica and add more as users grow.
The MIT KDC is an event-driven process: one process serves many connections at once, so adding threads in one process isn't the main way to increase throughput. A more realistic approach: run several instances behind a load balancer for large realms, adjust the service unit's file descriptor limits, and restrict the served ports via kdc_ports or kdc_tcp_ports in krb5kdc.conf.
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88Leaving both ports active gives a fallback when one protocol is blocked by the network, and is usually the best choice.
Several caching layers can be leveraged:
Overly aggressive caching delays awareness of changes; with no caching at all, the KDC is flooded with requests that could have been answered once.
Performance isn't only about the KDC. How the client requests, stores, and uses credentials heavily determines the user experience.
The credential cache (ccache) is where tickets are stored on the client side. The type of cache chosen affects both performance and security:
chmod 600).The tunable value: default_ccache_name in krb5.conf. For servers with many processes using the same credentials, the right ccache choice reduces repeated lookup costs.
A client contacting the KDC at every login performs a DNS lookup to find the KDC; without caching, each login triggers one or more DNS requests. Enabling DNS caching on the resolver side (e.g. systemd-resolved, dnsmasq, or unbound) helps a lot in environments with many machines. Conversely, only set dns_lookup_kdc when using SRV records — a static KDC list in krb5.conf is actually faster.
For applications that authenticate via GSSAPI frequently, avoid building a security context from scratch on every request. A common pattern: use one ccache shared by processes on the same machine, keep service tickets while they're valid, and refresh tickets before they expire for long-lived connections (see k5start in episode 9).
When a client gives up contacting the KDC is governed by timeout and retry parameters. The MIT defaults are conservative to stay reliable on bad networks, but can be set more aggressively for reliable ones:
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_kdc = false
max_retries = 3
kdc_timeout = 3000max_retries limits the number of attempts to the KDC; kdc_timeout sets the wait time (in milliseconds) per attempt. Small values speed up failure detection and failover to a replica, but values that are too small make a client give up before a slow KDC answers.
The network is where much of Kerberos latency actually happens.
Kerberos runs over two transport protocols, each with trade-offs:
| Aspect | UDP | TCP |
|---|---|---|
| Messages | Suited for short request/reply | Needed for large messages (full AS reply) |
| Overhead | Low, no handshake | There's a handshake, more bytes per session |
| Reliability | Messages can be lost; retry on the app side | Guaranteed in-order delivery |
| Failure | Easy to "not be heard" behind a firewall | Connection failures are clearly visible |
| Fit | Default for common AS/TGS requests | Used when replies exceed the UDP limit |
MIT picks the protocol based on an estimated reply size; this limit is set via udp_preference_limit. A large value makes the client lean toward UDP; a small value or zero forces TCP.
An AS reply can be large — holding a session key, the TGT ticket, and supporting data. When it exceeds the MTU, the UDP packet is fragmented and the risk of loss rises. Make sure the end-to-end MTU is consistent (especially over tunnels/VPNs) and reduce per-reply payload with compact encryption. Don't set the UDP limit too high if the network can't guarantee large packets get through.
Each login involves several round-trips — to the KDC for a TGT, to the KDC for a service ticket, then to the service server — and every round-trip adds latency. Placing the KDC near clients cuts latency dramatically; this is a big theme in episodes 25 and 26.
If there are several KDCs, load can be balanced via priority and weight in DNS SRV, distributing different KDC lists to client groups, or a network load balancer in front of the KDC pool. Whatever the method, make sure health checks monitor the real condition, not just the port status.
Encryption is the most computationally expensive part of Kerberos; every successful request involves several cryptographic operations on the CPU.
Modern processors include AES-NI instructions that accelerate AES operations. A KDC built with OpenSSL uses this acceleration automatically. To verify, run:
openssl speed -evp aes-128-cbc
openssl speed -evp aes-256-cbcIf the results are far below that hardware's expectations, the CPU or OpenSSL build probably doesn't have AES-NI enabled (e.g. a VM without the aes flag). Check /proc/cpuinfo — openssl is a friend for this quick verification.
Each encryption type (enctype) has a different cost and strength:
| Enctype | Strength | Cost | Notes |
|---|---|---|---|
aes256-cts-hmac-sha1-96 | High | Medium | Common modern standard |
aes128-cts-hmac-sha1-96 | Good | Lighter | Choice when CPU is limited |
aes256-cts-hmac-sha384-192 | Very high | Heavier | Newest, check all-party support |
rc4-hmac | Weak | Light | Legacy, should be disabled |
The enctype list is set via permitted_enctypes in krb5.conf and supported_enctypes on the KDC side. Restricting the list reduces negotiation space and prevents fallback to weak algorithms.
The basic law: the stronger the key, the more expensive the CPU. aes256 gives a larger security margin than aes128, but is heavier; in a realm with thousands of logins per minute this difference accumulates. Balance it: aes256-cts-hmac-sha1-96 as the standard, aes128 as the secondary enctype for CPU-sensitive clients, and disable rc4-hmac. Never lower encryption strength for performance if it opens the door to algorithms that are no longer secure.
A tidy configuration is useless if the hardware doesn't match the load.
KDC requirements are driven by three things: CPU for encryption (the main reason to pick an AES-NI-capable CPU), memory for the database and memory mapping, and disk for the database, logs, and backup dumps. The KDC is a light service — one VM with a few modern vCPUs comfortably serves a realm of hundreds of users. Problems appear at peak load, not at idle.
Start from a simple question: how many users and service principals are there? How often do they log in or request new tickets? Are there peak periods? A common pattern: most logins concentrate in certain hours, and batch authentication (pipelines, backups, agents) often dominates KDC load more than interactive users. That determines the requirement, not the total user count.
Plan capacity for peaks, not averages: a login storm when all users log in at the same hour, failover when one KDC dies and the entire load jumps to the survivors, and a rollout of a new application introducing many simultaneous authentications.
When a single KDC is strained, escalate the response gradually: tune the configuration first (enctypes, timeouts, caching), then add replicas as the cheapest horizontal capacity, upgrade the master hardware for write load, and finally redesign the architecture to a hierarchical realm when scale exceeds a single realm (theme of episode 26).
Episode 24 provided a Kerberos performance tuning map: database and caching optimization on the KDC side, replicas for load distribution, worker and connection limit adjustments, ccache and DNS efficiency on the client side, the TCP vs UDP choice, AES-NI acceleration and enctype selection, and capacity planning for peak scenarios.
Key takeaways:
In the next episode, episode 25, you step up a level toward reliability: High Availability — arranging KDC replicas with database propagation via kprop, automatic failover using DNS SRV, preventing split-brain, and preparing disaster recovery.