Skip to content

Start typing to search

Active Directory Guide: Architecture, DNS, Security

What Is Kerberos? Tickets, KDC, SPNs, and Troubleshooting

How Kerberos authenticates without sending passwords: the KDC, TGTs and service tickets, a real packet capture, klist, SPNs, and a diagnosis order for failures.

Written by

Kerberos is an authentication protocol that lets users and services on a network prove who they are to each other without sending passwords. It does it with time-limited tickets: a user proves their identity once at sign-in, receives a document valid for a set time, and for the rest of the day shows that document at every door instead of a password. That’s what runs behind every Active Directory sign-in, on port 88.

Advertisement

The name isn’t an accident. In Greek mythology, a three-headed dog guards the gate of the underworld ruled by Hades: Kerberos, or Cerberus. Its job is to check who passes, and passage depends not on who you are but on the valid document you carry. MIT took the name when it built the protocol within Project Athena, starting in 1983, because the design had exactly three parties. This article stays at that gate.

It covers what Kerberos is and who the three heads stand for, the KDC architecture that issues tickets, the message flow from sign-in to a file share, that same flow in Wireshark at packet level, the real tickets on a machine read with klist, and finally a diagnosis order from symptom to error code. It’s part of the Active Directory guide and assumes the DNS foundation from Active Directory DNS. If you have a system that can’t authenticate right now, jump to diagnosing Kerberos.

What Is Kerberos, and Where Does the Name Come From?

Kerberos is a ticket-based protocol that lets two parties prove their identity to each other over an untrusted network. The version in use today is Kerberos 5, defined in RFC 4120, which replaced RFC 1510 from 1993. Windows, Linux, macOS, and many enterprise applications speak the same protocol; Kerberos isn’t a Microsoft technology. What Microsoft did was make it the default authentication method of Active Directory.

Three Heads, Three Parties

The three heads stand for the three parties to authentication: the client, the service, and the KDC (Key Distribution Center) both of them trust. That triangle explains the whole protocol, because the problem Kerberos solves is this: how do two parties who have never met trust each other without exchanging passwords?

Everyday life already has the answer. Entering an office building, the security guard doesn’t know you and doesn’t need to. You show ID once in the lobby, you’re given a pass for the day, and you badge through every door with it. The door on the fifth floor doesn’t know you; it knows the pass, and it trusts whoever issued it.

That’s Kerberos’s architecture, and the consequence is the opposite of what most people expect: the service never asks the KDC to verify you. The ticket arrives encrypted with the service’s own key; if the service can open it, it knows the issuer really was the KDC. That detail is also why the protocol scales: across thousands of users and thousands of file accesses, the domain controller stays out of the traffic.

Why the Password Never Crosses the Network

Kerberos is designed so the password is never carried on the network. Instead, both sides turn the password into an encryption key, and each proves it knows the key by decrypting something. The password itself is in no message.

In the mid-1980s that was radical. Most protocols of the time sent usernames and passwords in plain text, readable by anyone on the same cable; Telnet and FTP still carry that flaw. Project Athena had to tie thousands of shared workstations on the MIT campus to one identity system, on a network where no machine could be trusted. Kerberos was born under that constraint.

The practical result holds today: an attacker listening to the network can’t pull a password out of Kerberos traffic. What they can capture is tickets, and tickets expire. In the Wireshark captures below, there isn’t a single readable password.

The Ticket Model: KDC, AS, and TGS

The KDC issues and distributes tickets; in Active Directory, every domain controller is also a KDC. It isn’t Windows-specific either: a Linux server running Samba as an AD domain controller issues the same tickets. The KDC has two jobs, defined as two services in the protocol, and knowing their names pays off directly in diagnosis.

AS (Authentication Service) verifies identity the first time. It’s the lobby ID check: you prove you know the key derived from your password and receive the pass you’ll use all day.

TGS (Ticket Granting Service) grants a specific door to whoever shows that pass. You badge at the floor you want, the system sees you’re allowed, and the door opens. TGS works on every new access; AS once per sign-in.

Where the two kinds of Kerberos ticket come from. The client first proves its identity to the AS part of the KDC and receives a TGT; this happens once per sign-in. Then, for each new service, it shows its TGT to the TGS part of the KDC, receives a service ticket for that service, and presents that ticket to the service; these three steps repeat for every service it reaches. client KDC AS + TGS service 1 · proving who I am 2 · TGT 3 · TGT + which service 4 · service ticket 5 · presenting the ticket to the AS once per sign-in to the TGS one per service opened by the service's key The AS runs once per sign-in; steps three to five repeat for every new service.
Two tickets, two issuers. The AS issues the TGT once per sign-in; the TGS issues a fresh service ticket for each new service, and only the target service's key can open it.

TGT vs. Service Ticket

Kerberos has two kinds of ticket, and mixing them up sends diagnosis the wrong way from the start.

PropertyTGTService ticket
Full nameTicket Granting TicketService Ticket
Issued byASTGS
Used forRequesting other ticketsReaching one service
How manyOne per sign-inOne per service used
Encrypted withThe krbtgt account’s keyThe target service account’s key
Default lifetime (AD)10 hours10 hours, never beyond the TGT

A TGT isn’t a key; it’s the right to ask for keys. Your lobby pass opens no door by itself. It only says “this person passed the lobby and was verified.” What opens a door is the door-specific permission obtained by showing that pass.

You live this every morning. At sign-in you’re asked for a password: that’s the AS step. During the day you reach the file server, the printer, the intranet, and nobody asks again; each time a separate service ticket is fetched in the background, and you never see it. That’s the mechanism behind single sign-on.

krbtgt: The Account That Signs Tickets

The key that encrypts every TGT is derived from the password of a special domain account called krbtgt. It exists in every Active Directory domain, never signs in, appears disabled, and does only this.

Why it matters, in one sentence: whoever obtains the krbtgt key can mint a valid TGT for any user in the domain, with any lifetime. That’s what attack literature calls a “Golden Ticket,” and it’s indistinguishable from one the KDC issued, because it’s signed with the same key.

How Kerberos Works: From AS-REQ to AP-REQ

The flow has three exchanges, each a request and a reply. The message names are fixed by the protocol; they’re what Wireshark shows and the prefixes of the error codes you’ll meet in event logs. All six messages, in order:

#MessageDirectionWhat happens
1AS-REQClient → KDCAuthentication request
2AS-REPKDC → ClientTGT delivered
3TGS-REQClient → KDCTicket request for a specific service
4TGS-REPKDC → ClientService ticket delivered
5AP-REQClient → ServiceTicket presented
6AP-REPService → ClientService proves itself (optional)

First Exchange: Proving Identity

AS-REQ is the client telling the KDC “I’m this user, give me a TGT.” In Active Directory, the request must contain a timestamp encrypted with a key derived from the user’s password. That’s called pre-authentication, and it’s mandatory by default.

“Must contain” matters, because the client doesn’t always do it on the first try. You’ll see what really happens in the Wireshark section: the real flow is one message longer than the textbook.

This first step is why Kerberos cares so much about time. The KDC decrypts the timestamp and compares it with its own clock; if the difference exceeds the tolerance, it refuses before authentication even starts. Active Directory’s default tolerance is 5 minutes. The reason is to stop an attacker replaying a captured request later: if the stamp is stale, the request is void. The dog at the gate reads the date on the document. The document can be genuine and its bearer really who they claim; if the date is off, nobody passes.

AS-REP carries two things. The first is the TGT, encrypted with the krbtgt key, so the client can’t open it; it only carries it. The second is a session key encrypted with the client’s own key, which the client can open. That asymmetry is the heart of the protocol: you can’t read the document in your hand, but you can present it.

Second Exchange: Getting a Service Ticket

TGS-REQ is the client showing its TGT and asking for a ticket to a specific service. The service is named by its SPN (Service Principal Name). For a file server, the requested SPN looks like cifs/fs01.ad.sercebilisim.com.

The KDC opens the TGT with its krbtgt key, and if it’s valid, looks up the requested SPN in the directory and finds the account it’s registered on. The service ticket returned in TGS-REP is encrypted with that account’s key.

That sentence is the key to the whole diagnosis section, so it’s worth repeating: the KDC encrypts the ticket with the key of whichever account it found the SPN on. If the SPN is registered on the wrong account, the ticket is still issued, still reaches the client, and no error appears; but the target service can’t open it, because it isn’t its key. The fault surfaces two steps later, with a completely different symptom.

Third Exchange: Going to the Service

AP-REQ is the client finally presenting the service ticket, and the key detail is that this message doesn’t go through the KDC. The client connects straight to the file server, web server, or SQL server and hands over the ticket.

The service opens the ticket with its own key. If it can, it has verified the KDC issued it, because nobody else knows that key. It reads the user identity and group memberships inside and makes its authorization decision. If the client asks for AP-REP, the service proves itself too; that’s mutual authentication, and it prevents connecting to an impostor server.

The practical consequence keeps paying off: in some Kerberos failures the domain controller is perfectly healthy and its logs show nothing, because the broken step never touched the DC. Searching logs without knowing which exchange failed means hours on the wrong server.

Watching Kerberos in Wireshark

Kerberos messages are visible on the network, and Wireshark decodes them by name. This section doesn’t explain the protocol; it shows it. Once you’ve seen the flow at packet level, you measure where a failure stops instead of guessing.

Everything below was produced in the author’s lab: domain ad.sercebilisim.com, domain controller dc01 (192.168.1.10), domain-joined Windows 10 client PCTEST01 (192.168.1.105).

Capture on the domain-joined client, not the DC. On the DC, every machine’s traffic mixes in and you can’t isolate your own session. Set the display filter to kerberos; it covers TCP and UDP on port 88 and lists messages by name.

Commands, screenshots, and outputs come from the author’s lab domain (ad.sercebilisim.com). For a clean flow, clear the machine’s existing tickets first so the client has to build the flow from scratch:

CMD
klist purge
klist get HOST/dc01.ad.sercebilisim.com
Wireshark with the kerberos filter listing the flow: AS-REQ, the pre-authentication rejection, AS-REP, and TGS-REQ with TGS-REP lines
The whole flow on one screen. The error on the second line isn't a fault; it's the gate asking "where's your seal?"

The Real Flow: One Message Longer Than the Textbook

Decoded with tshark, the capture looks like this. Three things to know first: each line is one message, and the leading number is the frame’s position in the capture; 192.168.1.105 is the client and 192.168.1.10 the domain controller; the name at the end is the message type, fixed by the protocol.

   25   2.647739  192.168.1.105 → 192.168.1.10   KRB5  305  AS-REQ
   31   2.649731  192.168.1.10  → 192.168.1.105  KRB5  423  KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED
   65   2.651290  192.168.1.105 → 192.168.1.10   KRB5  385  AS-REQ
   72   2.653078  192.168.1.10  → 192.168.1.105  KRB5  352  AS-REP
  115   2.655686  192.168.1.105 → 192.168.1.10   KRB5 1843  TGS-REQ
  126   2.658453  192.168.1.10  → 192.168.1.105  KRB5  345  TGS-REP
  223   4.699501  192.168.1.105 → 192.168.1.10   KRB5 1843  TGS-REQ
  234   4.701797  192.168.1.10  → 192.168.1.105  KRB5  345  TGS-REP
  1. Frame 25: the client asks for a TGT. This first attempt carries no proof, only the request.
  2. Frame 31: the KDC turns it down: KRB5KDC_ERR_PREAUTH_REQUIRED, “prove who you are first.”
  3. Frame 65: the client repeats the request, now with a timestamp encrypted with the key derived from its password.
  4. Frame 72: the KDC is satisfied and delivers the TGT.
  5. Frame 115: the client shows its TGT and asks for a ticket to a specific service.
  6. Frame 126: that service’s ticket arrives.
  7. Frames 223 and 234: the same exchange, for a second service.

The second line is the surprise. Textbooks describe six messages and assume the first request is accepted. In reality the client sends the first attempt empty, gets rejected, and comes back with proof. So seeing a KRB-ERROR in a Kerberos capture doesn’t by itself mean something is wrong. The rejection of the first AS-REQ appears in every healthy sign-in. What matters is the error code and whether the flow continues after it.

What’s Inside the Packets?

If there’s one field worth tracking, it’s sname, the service name: which service’s ticket this message is about. Its value tells you where in the flow you are:

  • krbtgt/... means the TGT. The client is still at the identity stage.
  • Anything else (HOST/..., ldap/..., cifs/...) means access to a specific service. Identity is done; now it’s the door.
FrameMessageRequested sname
25AS-REQkrbtgt/AD.SERCEBILISIM.COM
65AS-REQkrbtgt/AD.SERCEBILISIM.COM
72AS-REPkrbtgt/AD.SERCEBILISIM.COM
115TGS-REQkrbtgt/... and HOST/dc01.ad.sercebilisim.com
126TGS-REPHOST/dc01.ad.sercebilisim.com
223TGS-REQkrbtgt/... and ldap/dc01.ad.sercebilisim.com
234TGS-REPldap/dc01.ad.sercebilisim.com

Two names on the TGS-REQ lines isn’t a coincidence: Wireshark reports two message types in that frame, 12 (TGS-REQ) and 14 (AP-REQ). When the client shows its TGT to the KDC, it wraps it in an AP-REQ. So showing a TGT is itself presenting a ticket; at that moment the KDC behaves like any other service. “Show a document at every door” applies to the KDC’s own door too.

Opening the AS-REP makes the asymmetry visible. The dump below is a tree; indentation shows what’s inside what, and that’s the point. Look at cname (who received the ticket: PCTEST01$, the machine account), ticket (the ticket itself, whose sname says krbtgt, so it’s a TGT), the enc-part inside ticket, and the second enc-part one level outside it.

as-rep
    pvno: 5
    msg-type: krb-as-rep (11)
    padata: 1 item
        PA-DATA pA-ETYPE-INFO2
            etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
            salt: AD.SERCEBILISIM.COMhostpctest01.ad.sercebilisim.com
    crealm: AD.SERCEBILISIM.COM
    cname
        CNameString: PCTEST01$
    ticket
        tkt-vno: 5
        realm: AD.SERCEBILISIM.COM
        sname
            SNameString: krbtgt
            SNameString: AD.SERCEBILISIM.COM
        enc-part
            etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
            kvno: 2
            cipher: 4fcc2824c144df7f305d3758b80bce30...
    enc-part
        etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18)
        kvno: 4
        cipher: 573eb26fcbbf981b3a437287802fcff0...

One packet, two enc-part blocks, two different key numbers:

enc-partPositionkvnoWhose keyClient can open?
FirstInside ticket2The krbtgt accountNo
SecondOutside ticket4The client itselfYes

The KDC used two locks in one reply. The first seals the ticket body; only the KDC and the target service hold that key, so the client carries a block it can’t read. The second is for the client alone, and the session key comes out of it. A courier carrying a sealed envelope doesn’t know what’s inside, but can deliver it to the right office.

Tree view of a Kerberos AS-REP: the krbtgt sname inside the ticket and two separate enc-part blocks carrying different kvno values
The inner and outer seals were made with different keys. You can carry the document; you can't read it.

The salt is instructive too: AD.SERCEBILISIM.COM + host + the machine name. The password appears nowhere; what appears is the salt used to derive a key from it. Also note that this entire flow ran over TCP 88, not UDP. Kerberos uses both; Windows switches to TCP when a message exceeds a certain size, and in modern environments you’ll see most flows on TCP. Filter on UDP only and you’ll catch nothing.

The Third Exchange Goes to the Service, Not the KDC

In the capture above, AP-REQ only appeared wrapped inside TGS-REQ. To see the real third exchange, I opened a file share and captured again:

143  TGS-REQ  → 192.168.1.10:88    sname: cifs/dc01.ad.sercebilisim.com
154  TGS-REP  ← 192.168.1.10
235  SMB2 Session Setup Request → 192.168.1.10:445   sname: cifs/dc01.ad.sercebilisim.com
245  SMB2 Session Setup Response ← 192.168.1.10

Look at the ports; that’s the whole point. The client gets the cifs/dc01.ad.sercebilisim.com ticket from the KDC on 88, then presents it to the service on 445. In the second step no authentication question goes to the KDC; what goes is the ticket itself, embedded in the SMB session setup. “The service never asks the KDC” has its proof in these four lines: not one packet goes to port 88 while talking to the file server.

When the Clock Drifts: Measured, and Not What We Expected

The most instructive result came from an experiment. I deliberately set the client’s clock back 400 seconds (tolerance: 300) and captured the flow again. The expectation was clear: authentication would stop. Here’s what happened:

33   AS-REQ                                        →
39   KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED       ←   error-code: 25
73   AS-REQ (timestamped, clock 400 s behind)      →
79   KRB Error: KRB5KRB_AP_ERR_SKEW                ←   error-code: 37
113  AS-REQ (again)                                →
120  AS-REP                                        ←   SUCCESS
  1. Frame 33: the usual empty request.
  2. Frame 39: the familiar rejection, “add proof” (error-code: 25).
  3. Frame 73: the client adds the timestamp, but its clock is 400 seconds behind, so the stamp is wrong.
  4. Frame 79: the KDC rejects it, this time because of the clock: KRB_AP_ERR_SKEW, error-code: 37.
  5. Frame 113: the client tries once more.
  6. Frame 120: and gets the ticket.

With the clock still 400 seconds behind, klist get succeeded and the file share worked. The error was produced, but authentication didn’t stop. The reason sits in the error packet:

krb-error
    msg-type: krb-error (30)
    stime: Aug  7, 2026 21:10:09
    error-code: eRR-PREAUTH-REQUIRED (25)

When the KDC sends an error, it includes its own time (stime). The Windows client reads it, adjusts its Kerberos timestamp to the KDC’s clock, and retries. The protocol can compensate for clock skew within a single round.

A Kerberos KRB-ERROR packet with error-code eRR-SKEW 37 and the stime field showing the KDC's own clock
The gate refuses the document, and in the same breath tells you the correct date. That field is what lets the client recover.

The field translation: “the clock drifted, so Kerberos stopped” isn’t true everywhere. On a network with Windows clients, sign-in can keep working with minutes of skew while the failure shows only on certain devices. Some of the “works for one user, not the other” authentication faults come from exactly this. The dog refused the document’s date, but told the traveler the right one; the traveler fixed it and walked in. The gate is strict, not deaf.

Reading Tickets: klist, Lifetimes, and SPNs

klist lists the Kerberos tickets currently cached on a Windows machine. It ships with Windows, and diagnosis starts here, because whether a ticket exists splits the whole flow in two. The real output from PCTEST01 in the lab:

Current LogonId is 0:0x3e7

Cached Tickets: (2)

#0>     Client: pctest01$ @ AD.SERCEBILISIM.COM
        Server: krbtgt/AD.SERCEBILISIM.COM @ AD.SERCEBILISIM.COM
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
        Start Time: 8/7/2026 20:53:27 (local)
        End Time:   8/8/2026 6:53:27 (local)
        Renew Time: 8/14/2026 20:53:27 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0x1 -> PRIMARY
        Kdc Called: dc01.ad.sercebilisim.com

#1>     Client: pctest01$ @ AD.SERCEBILISIM.COM
        Server: HOST/dc01.ad.sercebilisim.com @ AD.SERCEBILISIM.COM
        KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
        Ticket Flags 0x40a50000 -> forwardable renewable pre_authent ok_as_delegate name_canonicalize
        Start Time: 8/7/2026 20:53:27 (local)
        End Time:   8/8/2026 6:53:27 (local)
        Renew Time: 8/14/2026 20:53:27 (local)
        Session Key Type: AES-256-CTS-HMAC-SHA1-96
        Cache Flags: 0
        Kdc Called: dc01.ad.sercebilisim.com

These two entries are the two ticket types from earlier. Two ways to tell them apart, both in this output:

  • The Server field. #0 says krbtgt/AD.SERCEBILISIM.COM: the right to ask for tickets, a TGT. #1 says HOST/dc01.ad.sercebilisim.com: access to one service, a service ticket.
  • The initial flag, only on #0. It says the ticket came directly from password verification; service tickets don’t carry it, because they were obtained by showing a TGT.

The times confirm the theory: Start Time 20:53:27, End Time the next morning at 6:53:27, exactly 10 hours. Renew Time a week later, exactly 7 days. Both are Active Directory defaults. Also worth reading: the encryption types (AES-256 here; RC4-HMAC would mean an old configuration and a hardening candidate), ok_as_delegate (the service may carry the client’s identity on to another service), and Kdc Called, the DC that issued the ticket, the first field to check where there are several DCs.

klist tgt shows only the TGT; klist purge clears the cache harmlessly, since tickets are fetched again on the next access.

Where Ticket Lifetimes Are Set

Lifetimes are set in domain policy, not on machines: Computer Configuration > Windows Settings > Security Settings > Account Policies > Kerberos Policy.

SettingDefaultWhat it does
Enforce user logon restrictionsEnabledKDC checks each ticket request against the user’s logon rights
Maximum lifetime for service ticket600 minutesService ticket lifetime
Maximum lifetime for user ticket10 hoursTGT lifetime
Maximum lifetime for user ticket renewal7 daysRenewal window
Maximum tolerance for computer clock synchronization5 minutesClock tolerance
Group Policy Management Editor showing the Kerberos Policy branch with the default ticket lifetimes and clock tolerance
A ticket's lifetime isn't set on the machine; it's in the organization's written rules.

Know what you gain and give before changing these. Longer lifetimes reduce KDC load and add comfort, and lengthen how long a stolen ticket works. The misguided change I see in the field almost always goes one way: a fault appears, the tolerance or lifetime is raised, the fault is hidden, and the cause stays.

What Is an SPN? The Most Often Misconfigured Part

An SPN is a service’s name in the Kerberos world, written service-class/host. cifs/fs01.ad.sercebilisim.com is a file share, HTTP/portal.ad.sercebilisim.com a web application, MSSQLSvc/sql01.ad.sercebilisim.com:1433 a SQL instance.

One rule, and every SPN fault breaks it: an SPN may be registered on only one account in the domain. When the same SPN appears on two accounts, the KDC can’t choose and refuses to issue a ticket.

setspn -L lists an account’s SPNs. The real output for the lab client (the OU names are Turkish because the lab’s OU tree was built for the Turkish original: Bilgisayarlar means Computers, Genel_Mudurluk Head Office, Lokasyonlar Sites):

Registered ServicePrincipalNames for CN=PCTEST01,OU=Bilgisayarlar,OU=Genel_Mudurluk,OU=Lokasyonlar,DC=ad,DC=sercebilisim,DC=com:
        WSMAN/PCTEST01
        WSMAN/PCTEST01.ad.sercebilisim.com
        RestrictedKrbHost/PCTEST01
        HOST/PCTEST01
        RestrictedKrbHost/PCTEST01.ad.sercebilisim.com
        HOST/PCTEST01.ad.sercebilisim.com

The pattern is the same on every machine account, and once you see it SPNs make sense: every name is registered twice, short name and FQDN. A client can connect as \\PCTEST01 or \\PCTEST01.ad.sercebilisim.com, and the KDC must find whichever form was requested. Registering one form and forgetting the other is the most common cause of “works with the short name, not with the FQDN.”

Scan the whole domain for duplicates:

CMD
setspn -X

A healthy environment ends like this:

Checking domain DC=ad,DC=sercebilisim,DC=com
found 0 group of duplicate SPNs.

Duplicate SPNs are always born the same way: an application is installed under one service account, the account is changed, and the old SPN isn’t removed. Or an app moves from the machine account to a dedicated service account. Both accounts claim the same name, and from then on Kerberos doesn’t work for that service; authentication silently drops to NTLM.

Diagnosing Kerberos: From Symptom to Error Code

Kerberos failures are hard to diagnose because the error messages never say “Kerberos.” Users say “I can’t sign in,” “I can’t open the share,” or “the application keeps asking for my password.” The screen talks about trust relationships, access denied, or an unreachable domain. Getting down to the authentication layer is the technician’s call; the message won’t lead you there. So diagnosis starts from the symptom, not the error code:

SymptomLikely layerCheck first
Nobody can sign in, “domain unavailable”Name resolution or timeSRV records, clock offset
Sign-in works, one application asks for a passwordSPNsetspn -X
Works on some machines, not othersTime or encryption typew32tm /stripchart, KRB-ERROR code

When you have an error code, here’s what it means. Numbers are included, because Wireshark’s kerberos.error_code field shows the number, not the name:

CodeNo.MeaningReal cause
KDC_ERR_PREAUTH_REQUIRED25Pre-authentication requiredNot an error; the first step of every healthy flow
KRB_AP_ERR_SKEW37Clock skew beyond toleranceClient or server time source broken
KDC_ERR_PREAUTH_FAILED24Pre-authentication failedWrong password or locked account
KDC_ERR_S_PRINCIPAL_UNKNOWN7Requested SPN not foundSPN never registered
KDC_ERR_PRINCIPAL_NOT_UNIQUE8SPN on more than one accountDuplicate SPN
KDC_ERR_ETYPE_NOSUPP14Encryption type not supportedClient and account encryption settings diverged
KRB_AP_ERR_MODIFIED41Service couldn’t open the ticketSPN on the wrong account; keys don’t match

The first two rows were produced deliberately in the lab and verified at packet level; the rest come from Microsoft’s troubleshooting documentation. The first row is there because 25 isn’t a failure code, yet the first reflex on seeing it in a capture is to treat it as one.

Kerberos vs. NTLM, and the Silent Fallback

When Kerberos fails, Windows usually doesn’t show an error: it falls back to NTLM. NTLM predates Kerberos and uses no tickets; client and server run a challenge/response exchange, and the domain controller is asked on every access.

PropertyKerberosNTLM
MethodTime-limited ticketChallenge/response
DC consultedOnly when getting a ticketOn every access
Mutual authenticationYesNo
Needs a service nameYes (SPN)No

The last row is the point. NTLM doesn’t need an SPN, so when an SPN is misconfigured, things keep working. The user gets in, nobody reports a fault, and a service with Kerberos effectively disabled quietly carries on. That’s why SPN errors go unnoticed for months.

Check for the fallback by asking for the ticket:

CMD
klist get cifs/fs01.ad.sercebilisim.com

If a ticket comes back, Kerberos works. If you get KDC_ERR_S_PRINCIPAL_UNKNOWN but the application still opens, the fallback happened. On the server side, sign-in events in the Security log show Authentication Package as NTLM instead of Kerberos. Where the document system fails, the gate doesn’t close; it reverts to the old way, the guard asking whether they know you. It works, but it leaves no trail and it’s weaker.

Diagnosis Order

Keep this order: each step is the prerequisite for the next, and examining an upper layer while a lower one is broken wastes time.

1. Can the KDC be found? Clients find domain controllers through SRV records in DNS. Without them, Kerberos never starts.

CMD
nslookup -type=SRV _kerberos._tcp.ad.sercebilisim.com

The output should show dc01.ad.sercebilisim.com and port 88. If not, the problem is DNS, not Kerberos; see Active Directory DNS.

If the query comes back empty but you’re sure the DC is healthy, ask the same question over TCP before accepting the result:

PowerShell
Resolve-DnsName _kerberos._tcp.ad.sercebilisim.com -Type SRV -Server 192.168.1.10 -TcpOnly

DNS uses UDP by default, and UDP is open to interception along the path. Many home routers and some corporate security appliances transparently redirect UDP port 53 to their own resolver; you think you’re asking your internal server while the answer comes from elsewhere. TCP isn’t intercepted the same way. If the two transports give different answers, the problem isn’t your DNS server; it’s on the path. A quick confirmation: send a query to an address with no DNS server on it. If an answer comes back, whatever produced it isn’t the machine you asked. The lab measurement of exactly this, the same name returning two different addresses over UDP and TCP, is in What Is DNS?

2. Are the clocks close? Beyond 5 minutes the flow stops at the first message.

CMD
w32tm /stripchart /computer:dc01.ad.sercebilisim.com /samples:5 /dataonly

When you find skew, the reflex is w32tm /resync /force, and it will probably say “The command completed successfully.” Measure again, and the offset may not have moved at all. That’s exactly what happened in the lab: a 128-second offset stayed the same before and after the resync, with no error from the service (Last Sync Error: 0). The reason is in the Windows Time setting MaxAllowedPhaseOffset:

MaxAllowedPhaseOffset: 300
Phase Offset:          -128.3335403s
State Machine:         1 (Hold)

When the offset is larger than this threshold, Windows corrects the clock at once (a step); when it’s smaller, it doesn’t, and slowly closes the gap by changing the clock rate (slewing). 128 seconds was under the threshold, so the service decided there was no hurry and sat in Hold.

Now look at two numbers together: Windows’ step threshold is 300 seconds, and Kerberos’s tolerance is 300 seconds. The same number. The system therefore crosses its most dangerous zone most quietly: an offset just under 300 isn’t urgent to Windows, gets slewed over hours with no warning, and sits one step from Kerberos’s breaking point. Drift a little further and authentication stops suddenly, with no symptom beforehand. So look not at the output of resync but at the measurement after it. If the offset didn’t drop, lower the threshold temporarily to force a step, then put it back to 300.

The same measurement turned up a second problem, on the other end of the chain, and the Turkish original leaves it out. Checking where dc01 itself got its time, the answer was nowhere: its status reported Source: Local CMOS Clock, reference ID LOCL, and stratum 1. The domain’s PDC emulator, the one machine every other clock in the domain follows, was taking its time from its own hardware clock and announcing itself as a top-level authority. At that moment it happened to be within 0.39 seconds of the lab’s NTP server and of time.windows.com, so nothing was broken. But that was luck, not design: the lab has an NTP server fed from a national time source precisely so that the PDC can follow it, and the PDC wasn’t.

Two things make this worth checking on your own domain:

  • Nothing warns you. A PDC on its local clock produces no error. Every member syncs to it happily, Kerberos works, and the whole domain drifts together; skew between machines stays small because they all share the same wrong clock. It shows up only against the outside world: certificates, cloud sign-ins, log correlation with external systems.
  • It’s the step the time chain assumes and nobody checks. The chain is simple (the PDC emulator follows an outside source, everyone else follows the PDC emulator), and the first half is the one that’s quietly missing. On the PDC emulator, w32tm /query /source should name an NTP server, not Local CMOS Clock, and w32tm /query /status should show a stratum below that server’s, not 1.

3. Can a TGT be obtained? Whether there’s a TGT tells you if the failure is at the AS stage or later.

CMD
klist tgt

4. Can a service ticket be obtained? A TGT without a service ticket puts the problem on the SPN side.

CMD
klist
setspn -X

5. Which message does it stop at? If it’s still unclear, capture with Wireshark and match the error-code in the KRB-ERROR message to the table above.

The value of this order: up to step four you haven’t touched a server or changed a setting, and you’ve measured which layer the fault is in. The most expensive Kerberos mistake is acting before measuring. Raising the tolerance, recreating the account, or removing and re-adding the machine to the domain usually doesn’t remove the cause; it just hides the symptom for a while.

Advertisement

Conclusion: The Dog at the Gate Knows Nobody

What makes Kerberos hard to understand isn’t complexity but invisibility. When it works, nobody notices; a user types a password in the morning, is never asked again, and never thinks about the six messages behind it. When it breaks, it doesn’t introduce itself; it looks like something else failing.

The chain built here closes that gap: from the name to the three parties, from the parties to the ticket model, from tickets to six messages, from messages to error codes. Facing a Kerberos fault, the question is no longer “why doesn’t Kerberos work” but “which message did the flow stop at.” The second can be measured; the first can’t.

The dog at the gate doesn’t know you and doesn’t need to. It looks only at the document: is it valid, is the date right, did the right authority issue it. That’s what makes authentication trustworthy: a system based on recognizing people can be fooled, while a system based on documents can only be fooled if the document is forged. Kerberos’s whole design is about making that document unforgeable, and, as the lab’s PDC showed, it still depends on someone checking where the clock gets its time.

Questions about Kerberos

No. If you have Active Directory, Kerberos is already running: the KDC starts when a domain controller is promoted, and every domain-joined machine uses Kerberos by default. The only thing that needs configuring is SPN registration for service accounts, and only when you run your own application under a domain identity.
Very likely, and usually the cause is a missing SPN or one registered on the wrong account. When no Kerberos ticket can be obtained, Windows silently falls back to NTLM; if NTLM also fails, the user gets a password prompt. It looks like an application fault, but authentication dropped a level. Check setspn -X for duplicates first.
A stolen ticket works until it expires, so lifetime is a security setting. Active Directory defaults to 10 hours for a user ticket and a 7-day renewal window: one working day, and one week without another password prompt. Longer lifetimes add comfort and widen the window in which a stolen ticket is useful.
The Active Directory default tolerance is 5 minutes, part of the protocol's protection against replay. Beyond it the domain controller answers with KRB_AP_ERR_SKEW. Windows clients can often recover within one round because the error carries the KDC's own time, but many non-Windows clients can't. Fix the time source rather than raising the tolerance.

This article is adapted from a guide the author first published in Turkish on sercebilisim.com: Kerberos Nedir? Kimlik Doğrulama ve Bilet Mantığı

Advertisement

Written by

İlker Pehlivan

Network and systems engineer, founder of Serçe Bilişim

I run the networks and servers that other people's work depends on. Before founding my own consultancy I administered the backbone network, firewalls and core systems of a large multi-site organisation with thousands of users. I write about the things that actually broke.