Logins, SIDs, and Kerberos from First Principles, Part 1: What a SID Actually Is

Ask SQL Server who you are and it will answer with a name. Ask it to make a decision about you, though, and it uses something else entirely: a security identifier, or SID. Names are for humans. SIDs are what every permission check, every database user mapping, and every ownership chain actually compares. When logins misbehave, orphaned users, mysterious permission failures after a restore, service accounts that stop authenticating, the root cause is almost always a SID that does not match what something expected.

Illustration of anthropomorphized account cards queueing at a passport control desk where a DBA inspects passports showing barcode strips of varying lengths, representing SQL Server SIDs

This is part 1 of a series that builds SQL Server authentication up from first principles: what SIDs are, how they break, how to migrate logins without losing them, and how Kerberos fits in. Later parts cover what happens when a Windows account is dropped and recreated, migrating logins between servers with their SIDs intact, and why your connections silently fall back from Kerberos to NTLM. Everything below was run against SQL Server 2019 (CU32) and cross-checked on SQL Server 2025 (RTM).

Every Server Principal Has One

The sys.server_principals catalog view exposes the SID for every login, role, and mapped account on the instance.[2] A quick census by principal type:

A representative sample of the output:

Four different lengths, four different stories:

  • 1 byte: fixed, well-known principals. sa is 0x01 on every SQL Server instance on the planet. Server roles get similar single-byte identifiers.
  • 16 bytes: SQL logins. When you run CREATE LOGIN ... WITH PASSWORD, SQL Server generates a random 16-byte value (it is a GUID under the covers). Nothing outside this instance knows or cares about it, which becomes very important in part 3.
  • 28 bytes: Windows accounts and groups. This is a genuine Windows security identifier, issued by the domain controller (or the local machine), and SQL Server stores it verbatim. SQL Server did not invent this value and cannot change it.
  • 32 bytes: virtual service accounts (NT SERVICE\...). These are S-1-5-80 SIDs, deterministically derived from a SHA-1 hash of the service name. The same service name produces the same SID on every machine.[1]

Reading a Windows SID

The string form of a Windows SID looks like this:

The three middle values identify the issuing authority: a domain, or a standalone machine. Every account that authority creates shares those values. The final component, the relative identifier (RID), distinguishes individual accounts, and the authority hands them out sequentially: the first local account you create gets RID 1000-ish, the next one higher, and so on. A RID is never reused. That single fact drives everything in part 2.

The binary form SQL Server stores is the same data with the 32-bit words serialized little-endian. Take WORKSTATION01\FleetSvc from the output above and carve up the hex:

The last four bytes, F2030000, read backwards as 0x000003F2 = decimal 1010: the RID. Once you know to look at the tail of the binary SID, you can spot consecutively created accounts at a glance, and more usefully, you can spot when two SIDs that “should” match differ only in the RID.

Names Are Just a Lookup

Two built-in functions convert between the name and the SID:[3]

The round trip works, and it is tempting to conclude the name and the SID are interchangeable. They are not. The name is a label pinned to the SID, and the two can drift apart. SUSER_SID in particular has a subtle behavior with Windows accounts that will get its own treatment in part 2, because it has misled a lot of troubleshooting sessions.

SQL Login SIDs Are Random, Every Time

Here is the demonstration that sets up the rest of the series. Create a SQL login, capture its SID, drop it, and recreate it with the identical name and password:

Same name, same password, completely different identity. Every database user, every permission grant, every ownership record that referenced the original SID now points at a value that no longer exists. To SQL Server, the recreated login is a stranger who happens to have the same name, and the same thing happens with Windows accounts when someone deletes and recreates them in Active Directory, which is exactly where part 2 picks up.

Why This Layer Matters

Everything above sounds academic until you map it onto the failures it explains:

  • Orphaned database users are a SID in a restored database that matches no SID at the server level, even when the names line up perfectly.
  • Login migrations that silently break everything happen when the new server generates fresh random SIDs instead of carrying the old ones over.
  • “We recreated the account and now nothing works” is a new RID wearing an old name.

Each of those gets a dedicated post with reproducible demos. Next up: part 2 deletes a service account and recreates it, then watches two SQL Server instances disagree about who it is.

Questions about a SID mystery of your own? I would love to hear about it in the comments, or find me on Bluesky or LinkedIn.

References

  1. Security identifiers – Microsoft Learn. The structure of Windows SIDs, well-known SIDs, and the S-1-5-80 service SID scheme.
  2. sys.server_principals (Transact-SQL) – Microsoft Learn. The catalog view exposing the SID for every server-level principal.
  3. SUSER_SID (Transact-SQL) – Microsoft Learn. Name-to-SID conversion, including its behavior when the login already exists on the instance.