sql-login-syncer: Copy SQL Server Logins Without Losing SIDs or Passwords

Illustration of a woman engineer crossing a bridge between two server towers, carrying identical glowing keycards with matching fingerprint patterns

The Logins, SIDs, and Kerberos series spent three posts building up to a practical conclusion: SQL Server maps database users to logins by SID, not by name, and any login you recreate from scratch gets a new SID. Part 3 showed the cure for migrations: a CREATE LOGIN statement that carries the original password hash and the original SID, generated entirely from catalog views.

Running that generator by hand works fine for a one-time migration. It gets old quickly when you maintain Availability Group replicas or log shipping secondaries, where every new application login has to exist on every server in the topology with the same SID, or the next failover produces a crop of orphaned users.

So I turned the technique into a small open-source command-line tool: sql-login-syncer.

What It Does

Point it at a source instance and one or more targets:

For every syncable login on the source that does not exist on a target, it generates and executes the same DDL pattern from part 3:

The password arrives as the salted hash SQL Server already stores, so the tool never sees a plaintext password, and the SID arrives byte-for-byte identical, so database users in restored or failed-over databases map correctly on the first try.

A few details it handles along the way:

  • Windows logins and groups are created with FROM WINDOWS. Their SIDs come from Active Directory (or the local SAM), so as part 1 explained, SQL Server resolves the same SID on every server in the domain without any help.
  • Disabled logins are created disabled on the target, so a decommissioned-but-retained account does not spring back to life on a secondary.
  • Policy settings (CHECK_POLICY, CHECK_EXPIRATION), default database, and default language are carried over.
  • Fixed and internal principals are excluded: sa, NT SERVICE\... and NT AUTHORITY\... accounts, and ##...## certificate-mapped logins stay put.

What It Refuses to Do

The tool never modifies a login that already exists on a target. No password overwrites, no SID surgery, no drops. If a login exists on both servers, it is skipped, with one important exception in the reporting:

That warning is the vanishing service account problem in miniature: same name, different identity. A login like this looks synced, and every database you restore from the source onto that target will arrive with an orphaned user. Finding these mismatches before a failover is arguably worth more than the syncing itself.

Previewing with –script-only

If you would rather review the DDL before anything touches a production server (a sentiment I endorse), --script-only prints the generated statements without executing them:

You can also restrict a real sync to specific logins with --login, which takes a comma-separated list.

One caution: the scripted output contains password hashes. A hash is not a password, but a weak password’s hash can be cracked offline, so treat --script-only output with the same care as a backup file.

Permissions

Reading password hashes through LOGINPROPERTY(name, 'PasswordHash') requires CONTROL SERVER or membership in securityadmin on the source.[1] Without it, the function returns NULL and the tool reports an error for each SQL login rather than creating logins with wrong passwords. On each target you need ALTER ANY LOGIN. The tool uses Windows authentication only; there are no credentials to store or leak.

Where It Came From

The original version of this utility ran inside my server-maintenance framework and leaned on stored procedures in a central database to decide which servers were peers and to generate the DDL. This release genericizes it: the DDL generation moved into the tool itself (a query against sys.server_principals, sys.sql_logins, and LOGINPROPERTY[2]), and the target list became a command-line argument, so it runs against any SQL Server with no schema dependencies. It targets .NET 8 and was tested against SQL Server 2019 and SQL Server 2025.

The source, README, and MIT license are at code.hannahvernon.com/hannah-vernon/sql-login-syncer. Issues and pull requests are welcome.

If the SID mechanics underneath all of this are fuzzy, the series starts at part 1: what a SID actually is, and the migration technique the tool automates is walked through step-by-step in part 3.

References

  1. LOGINPROPERTY (Transact-SQL), Microsoft Learn.
  2. sys.server_principals (Transact-SQL), Microsoft Learn.