0x6: Kerberos KDC_ERR_C_PRINCIPAL_UNKNOWN — Username Doesn't Exist (4768)
Published
The domain controller could not find the requested account in its database — the name does not exist, and a run of these from one source is account enumeration.
Did the attacker have the password? No — the password (or username) was wrong.
Microsoft's definition
KDC_ERR_C_PRINCIPAL_UNKNOWN
Client not found in Kerberos database
Source: Microsoft event 4771 Kerberos error codes · checked against the published table on every build · look up another code
Where it appears
- Event 4768 (A Kerberos authentication ticket (TGT) was requested) on domain controllers: the Result Code field
- Microsoft Sentinel / Log Analytics: the Status column of the SecurityEvent table (EventID 4768)
What it means
When a client asks for a ticket-granting ticket, the KDC first looks up the client principal named in the request. Result code 0x6, KDC_ERR_C_PRINCIPAL_UNKNOWN — “Client not found in Kerberos database” — means that lookup failed: the name in the request does not match any principal the domain controller knows about. No key material was checked, so the code says nothing about any password; it is purely a statement about the name.
The code is carried in the Result Code field of event 4768 (A Kerberos authentication ticket (TGT) was requested), which Microsoft describes as “hexadecimal result code of TGT issue operation”. A successful TGT request carries 0x0. Event 4768 “generates only on domain controllers”, so this is a DC-side signal — collect it from every DC or you will see only part of the activity. Note also that 4768 “doesn’t generate for Result Codes: 0x10 and 0x18”; those wrong-password and pre-auth cases land in event 4771 / code 0x18 instead, which is why a name-guessing campaign is split across two event IDs.
The fields that matter for triage are Account Name (TargetUserName, the name that was not found), Client Address (IpAddress, recorded in the ::ffff:IPv4_address form — strip the prefix before comparing with your inventory), IpPort, and ServiceName, typically krbtgt/DOMAIN.
Is it an attack?
| Pattern | Reading |
|---|---|
| One or two 0x6 for a slightly misspelled name, then a 4768 with result 0x0 from the same host | A typo at a logon prompt |
| 0x6 for one name, repeating on a fixed interval from one internal server | A service, task or script still referencing a deleted or renamed account |
0x6 for a machine name ending in $ after a rebuild or domain removal | Stale computer object; verify the host was rejoined correctly |
| One client address, many distinct names that do not exist, in minutes | Account enumeration — Microsoft’s listed indicator for this code |
| 0x6 mixed with 4771 code 0x18 from the same source | Spraying with a name list: 0x18 marks the names that are real |
Kerberos name guessing is cheap and quiet — each miss is one UDP or TCP exchange with port 88 and produces no lockout, because nothing was ever authenticated. The names that come back as 0x18 instead of 0x6 are the attacker’s target list for the next stage. In event 4625 and in NTLM credential validation (event 4776), the matching Windows status is 0xC0000064 — the user name does not exist.
How to investigate
Rank source addresses by how many non-existent names each one tried:
SecurityEvent
| where TimeGenerated > ago(1d)
| where EventID == 4768 and Status =~ "0x6"
| extend ClientIp = replace_string(IpAddress, "::ffff:", "")
| summarize Attempts = count(), UnknownNames = dcount(TargetUserName),
NameSample = make_set(TargetUserName, 25),
FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
by ClientIp, Computer
| order by UnknownNames desc, Attempts desc
Then find the sources that hit both unknown names and real accounts — the signature of a list being worked through:
let unknownNames = SecurityEvent
| where TimeGenerated > ago(1d) and EventID == 4768 and Status =~ "0x6"
| extend ClientIp = replace_string(IpAddress, "::ffff:", "")
| summarize UnknownNames = dcount(TargetUserName), UnknownAttempts = count() by ClientIp;
SecurityEvent
| where TimeGenerated > ago(1d) and EventID == 4771 and Status =~ "0x18"
| extend ClientIp = replace_string(IpAddress, "::ffff:", "")
| summarize RealAccounts = dcount(TargetUserName), PreAuthFails = count(),
RealAccountList = make_set(TargetUserName, 20)
by ClientIp
| join kind=inner unknownNames on ClientIp
| project ClientIp, UnknownNames, UnknownAttempts, RealAccounts, PreAuthFails, RealAccountList
| order by UnknownNames desc
Finally, check whether any of those sources obtained a TGT afterwards:
let guessers = SecurityEvent
| where TimeGenerated > ago(1d) and EventID == 4768 and Status =~ "0x6"
| extend ClientIp = replace_string(IpAddress, "::ffff:", "")
| summarize LastMiss = max(TimeGenerated), Misses = count() by ClientIp;
SecurityEvent
| where TimeGenerated > ago(1d) and EventID == 4768 and Status =~ "0x0"
| extend ClientIp = replace_string(IpAddress, "::ffff:", "")
| join kind=inner guessers on ClientIp
| where TimeGenerated > LastMiss
| project TimeGenerated, Computer, TargetUserName, TargetDomainName, ClientIp, IpPort, Misses
| order by TimeGenerated asc
A TGT issued to an address that was just guessing names means an account answered: identify it, reset it, review the service tickets requested next (event 4769 from the same address), and treat an internal source host as compromised until you find the tool that generated the traffic. If the source is a known server and the same missing name repeats on a schedule, hunt for the stale reference instead. Exported Security logs can be grouped by account and client address in the free browser log analyzer, and the account-spraying patterns in the Windows 4625 password-spray rule translate directly to this DC-side data.
Related codes
- 0x18 KDC_ERR_PREAUTH_FAILED The domain controller rejected the pre-authentication data sent with a ticket request — Microsoft's listed cause is that the wrong password was provided; repeated 0x18 events for one account are a brute-force indicator.
- 0x10 KDC_ERR_PADATA_TYPE_NOSUPP
- 0x12 KDC_ERR_CLIENT_REVOKED The domain controller refused the ticket request because the account itself is barred from logging on — Microsoft's examples are an account that is disabled, expired or locked out — rather than because of anything about the password.
- 0x20 KRB_AP_ERR_TKT_EXPIRED
Detect it
Frequently Asked Questions
- Does 0x6 always mean the account never existed?
- Not necessarily. 0x6 means the KDC could not find that client principal in its database when the request arrived, which also covers accounts that were deleted or renamed and machine accounts removed from the domain. Check Active Directory for a recently deleted or renamed object with that name before you treat it as enumeration.
- How is 0x6 different from 0x18?
- 0x6 means the name was not found, so no credential was ever evaluated. 0x18 means the KDC found the account and rejected the pre-authentication data it was sent, which Microsoft attributes to the wrong password. A single source producing both is working through a name list and hitting a mix of real and invented accounts.
- How many 0x6 events should raise an alert?
- Microsoft gives a shape rather than a number: "0x6 (The username doesn't exist), if you see, for example N events in last N minutes. This can be an indicator of account enumeration attack, especially for highly critical accounts." Alert on distinct non-existent names per source rather than raw event counts, and lower the bar when the guessed names look like admin or service accounts.
- Will these attempts also appear as event 4625?
- Not reliably. Microsoft notes for both 4768 and 4771 that "This event generates only on domain controllers", and they record the Kerberos exchange itself, so a tool enumerating names against the KDC need not produce a 4625 on any member server. Pair 4625-based spray detections with a 4768 view of your domain controllers.
Find 0x6 in your own logs
Load a domain controller Security event export into the free browser analyzer to group Kerberos failures by account, source address and failure code (nothing is uploaded), or run it through LogTriage for threat-intel enrichment and an AI-written incident report.