Sqlmigration security review
Skill vanterx/mssql-performance-skills/skills/sqlmigration-security-review
Audits the security-object migration plan for a SQL Server move with 15 checks (J1-J15) — logins, server and database permissions, credentials, certificates/keys ownership, and Central Management Server registrations. Use this skill when a user is migrating a SQL Server database or instance and needs to carry over logins, permissions, credentials, or certificates, or asks "will my logins still work after migration" or "how do I migrate permissions." Trigger whenever security-object portability during a migration is the topic; dispatched here from /sqlmigration-review for the security-object family.From its SKILL.md
npx -y skills add vanterx/mssql-performance-skills --skill sqlmigration-security-reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
14.6 KB, as published. Nobody here has run it
sqlmigration-security-review
Purpose
Reviews the security-object family of a SQL Server migration — the slice sqlmigration-review
dispatches here rather than checking itself. This skill owns 15 checks (J1–J15) covering whether
logins, server/database permissions, credentials, certificate/key ownership, and Central
Management Server (CMS) registrations will survive a backup/restore or log shipping/Always On
AG seeding migration, and what breaks if they don't.
- Login Portability (J1–J5) — orphaned users after restore, SID mismatch, login type unsupported on target platform, password policy differences, default database missing
- Permission Fidelity (J6–J9) — server-level role membership, database-level role membership, explicit GRANT/DENY statements, ownership chains crossing the migration boundary
- Credentials & Secrets (J10–J12) — SQL Server Credential objects, proxy account mapping, linked server stored logins
- Certificates & Keys (J13–J14) — certificate/key migration for objects that depend on them
(excluding TDE, which is
sqlencryption-review's domain), backup of certificates before cutover - CMS (J15) — Central Management Server registration entries pointing at the old instance name
All fix recipes use native T-SQL system views (sys.server_principals, sys.database_principals,
sys.credentials), the in-box SqlServer PowerShell module, and the native sp_help_revlogin
script — no third-party module is referenced or required.
Input
Accepts any of the following:
- Source and target server facts pasted as text — login lists, permission grants, target platform
- Capture script output (
.txt/.csv) — seescripts/capture-security-facts.sql - Natural-language description — "migrating 40 logins, half are Windows groups, target is Azure SQL Database"
- File path to a directory of exported artifacts —
sp_helploginstext dumps, SSMS Generate Scripts output for logins/users
Recommended capture (run on the source instance):
SELECT name, type_desc, is_disabled, default_database_name,
SUSER_SID(name) AS sid
FROM sys.server_principals
WHERE type IN ('S','U','G') AND name NOT LIKE '##%';
SELECT dp.name AS user_name, dp.type_desc, sp.name AS login_name
FROM sys.database_principals dp
LEFT JOIN sys.server_principals sp ON dp.sid = sp.sid
WHERE dp.type IN ('S','U','G');
SELECT name, credential_identity FROM sys.credentials;
-- TDE encryptor certs also have is_active_for_begin_dialog = 0, so anti-join the DEK view to drop them
SELECT c.name, c.certificate_id, c.expiry_date, c.pvt_key_encryption_type_desc
FROM sys.certificates c
WHERE NOT EXISTS (SELECT 1 FROM sys.dm_database_encryption_keys dek
WHERE dek.encryptor_thumbprint = c.thumbprint);
Category 1 — Login Portability
J1 — Orphaned Database User After Restore
Trigger: A database user's SID (sys.database_principals.sid) has no matching login SID
(sys.server_principals.sid) on the target instance after restore.
Severity: Critical
Fix: Run ALTER USER [username] WITH LOGIN = [username]; for each orphaned user once the
matching login exists on the target, or use sp_help_revlogin's generated script to recreate
logins with matching SIDs before the restore completes.
J2 — SQL Authentication Login SID Mismatch Risk
Trigger: Migration plan creates new SQL-authentication logins on the target manually (e.g.,
via CREATE LOGIN) rather than scripting them from the source with matching SIDs.
Severity: Critical
Fix: Generate the login-creation script from the source using sp_help_revlogin (in-box
system stored procedure, or its documented script form), which preserves the original SID and
hashed password — manually re-typing CREATE LOGIN statements produces a new SID and orphans
every database user mapped to that login.
J3 — Login Type Unsupported on Target Platform
Trigger: Source has Windows-authenticated logins/groups, certificate-mapped logins, or
asymmetric-key-mapped logins, and the target platform is Azure SQL Database (no Windows Auth
support) or otherwise cannot host that login type.
Severity: Critical
Fix: Map Windows logins to Microsoft Entra ID identities for Azure SQL Database targets;
confirm certificate/key-mapped login support on the specific target platform before migrating —
see /sqlmigration-review Y8 for the broader Azure platform check.
J4 — Password Policy / Expiration Settings Differ From Source
Trigger: Source logins have CHECK_POLICY/CHECK_EXPIRATION settings that depend on a
domain password policy not enforced identically on the target (e.g., target is a workgroup
server or Azure SQL Database with no domain policy).
Severity: Warning
Fix: Re-evaluate each migrated login's CHECK_POLICY/CHECK_EXPIRATION settings explicitly
on the target rather than assuming the source's domain policy carries over silently.
J5 — Migrated Login's Default Database Does Not Exist on Target
Trigger: A login's default_database_name references a database that either was not part of
the migration scope or has a different name on the target.
Severity: Warning
Fix: ALTER LOGIN [loginname] WITH DEFAULT_DATABASE = [target_db_name]; for each affected
login after the database has been migrated and renamed (if applicable).
Category 2 — Permission Fidelity
J6 — Server-Level Role Membership Not Re-Created
Trigger: Source login is a member of a fixed or user-defined server role
(sys.server_role_members), and the migration plan's login-recreation script does not include
role membership statements.
Severity: Critical
Fix: Script ALTER SERVER ROLE [rolename] ADD MEMBER [loginname]; for every server-role
membership captured on the source, and run it immediately after login creation on the target.
J7 — Database Role Membership Lost on User Recreation
Trigger: A database user is a member of a database role (sys.database_role_members), and
the orphaned-user fix (J1) recreates the user without reassigning role membership.
Severity: Warning
Fix: Capture sys.database_role_members before migrating and re-run
ALTER ROLE [rolename] ADD MEMBER [username]; for each membership after fixing orphaned users.
J8 — Explicit Object-Level GRANT/DENY Not Captured in Migration Scripts
Trigger: sys.database_permissions shows explicit (non-role-based) GRANT or DENY statements
on objects within the migrated database, and the migration plan only scripts logins/users, not
explicit permissions.
Severity: Warning
Fix: Script sys.database_permissions joined to sys.database_principals and object/schema
names before migrating, and replay the explicit GRANT/DENY statements after the database and
users exist on the target — explicit grants are not implied by role membership and will be
silently lost otherwise.
J9 — Cross-Database Ownership Chain Breaks at Migration Boundary
Trigger: A stored procedure or view in the migrated database references objects in a
different database via ownership chaining, and that second database is not in the same migration
scope or TRUSTWORTHY/ownership chaining settings differ on the target.
Severity: Warning
Fix: Identify cross-database ownership chains before migrating (sys.sql_expression_dependencies
filtered to cross-database references — capture-security-facts.sql Query 11 collects these per
database); either migrate both databases together or replace the
chain with an explicit permission grant plus a module signing certificate — do not enable
TRUSTWORTHY ON as a substitute, since it is a documented security risk.
Category 3 — Credentials & Secrets
J10 — SQL Server Credential Object Not Migrated
Trigger: Source has one or more sys.credentials entries (used by proxy accounts, CLR, or
external data sources), and the migration plan's script set does not include credential
recreation.
Severity: Critical
Fix: CREATE CREDENTIAL cannot be scripted with the underlying secret intact (SQL Server
does not expose stored secrets) — re-enter the credential's secret manually on the target using
CREATE CREDENTIAL [name] WITH IDENTITY = '<identity>', SECRET = '<secret>';, sourced from the
original secret store, not from the source instance.
J11 — SQL Agent Proxy Account References a Credential Not Yet Created
Trigger: msdb.dbo.sysproxies references a credential by credential_id, and the migration
order creates the proxy before the credential exists on the target.
Severity: Warning
Fix: Sequence the migration script to create the credential (J10) before the proxy account,
and re-map credential_id by name rather than by ID, since IDs are not guaranteed to match
across instances.
J12 — Linked Server Stored Login Not Migrated
Trigger: Source has sys.linked_logins mappings (impersonation or stored credentials for a
linked server), and the migration plan recreates the linked server definition without the
stored login mapping.
Severity: Warning
Fix: Script sp_addlinkedsrvlogin for each mapping captured in sys.linked_logins, supplying
the stored password again manually (it is not exposed by any system view) — see
/sqlmigration-objects-review for the rest of the linked server definition migration.
Category 4 — Certificates & Keys
J13 — Certificate-Backed Object Migrated Without Its Certificate
Trigger: Source has objects depending on a certificate (Service Broker, certificate-mapped
logins, module-signing certificates) per sys.certificates, and the certificate is not in the
migration plan's script set.
Severity: Critical
Fix: BACKUP CERTIFICATE [certname] TO FILE = '<path>' WITH PRIVATE KEY (FILE = '<path>', ENCRYPTION BY PASSWORD = '<password>'); on the source, then CREATE CERTIFICATE ... FROM FILE ... WITH PRIVATE KEY (...) on the target before the dependent objects are created. This excludes
TDE certificates — see /sqlencryption-review for the full TDE certificate migration sequence.
J14 — Database Master Key Not Backed Up Before Migration
Trigger: Migrated database has sys.symmetric_keys showing a database master key
(name = '##MS_DatabaseMasterKey##'), and no BACKUP MASTER KEY step appears in the migration
plan.
Severity: Critical
Fix: OPEN MASTER KEY DECRYPTION BY PASSWORD = '<password>'; BACKUP MASTER KEY TO FILE = '<path>' ENCRYPTION BY PASSWORD = '<password>'; on the source before migrating, then restore it
on the target with RESTORE MASTER KEY FROM FILE = '<path>' DECRYPTION BY PASSWORD = '<password>' ENCRYPTION BY PASSWORD = '<newpassword>'; — see /sqlencryption-review for the full DMK/SMK key
hierarchy migration sequence if this database uses Always Encrypted or column-level encryption.
Category 5 — CMS
J15 — Central Management Server Registration Points at Old Instance Name
Trigger: The migration changes the instance name or the listener name the application
connects through, and CMS registrations on the CMS host (managed via SSMS Registered Servers,
backed internally by msdb.dbo.sysmanagement_shared_registered_servers) still reference the
pre-migration name.
Severity: Info
Fix: Update the CMS registration's server name via the SSMS Registered Servers GUI — this is
the Microsoft-documented mechanism and the one to use by default. Unverified: the underlying
msdb.dbo.sysmanagement_shared_registered_servers table and a
sp_sysmanagement_update_shared_registered_server procedure are referenced in community
documentation of CMS internals, but Microsoft Learn does not publicly document this schema or
any T-SQL procedure for scripting CMS registration changes — treat any T-SQL-based update to
these objects as unsupported and verify against a non-production CMS host before relying on it,
or confirm current behavior against the CMS host's actual schema before scripting.
Output Format
## sqlmigration-security-review
### Summary
[2-3 sentences: login count, permission complexity, headline risk]
### Critical Issues
[J-checks with Critical severity — each as: **J# — Name**, evidence, impact, fix]
### Warnings
[J-checks with Warning severity]
### Info
[J-checks with Info severity, if any]
### Passed Checks
[J-checks evaluated and not fired]
### Not Assessed
[J-checks that could not be evaluated because the required input was not provided]
### Login/Permission Migration Script Checklist
[Ordered list of native-tool scripts to run: sp_help_revlogin output, role membership,
explicit grants, credentials, certificates, in dependency order]
---
Analyzed by: [model name] · [date/time]
Output Filters
--brief— Summary + Critical Issues only--critical-only— Critical Issues only
Verbose Output (--verbose)
When --verbose is passed, also write
output/sqlmigration-security-review/<timestamp>-J/analysis.md (full report) and trace.md
(which facts were available, which J-checks were skipped and why).
Notes
- This skill is strictly offline — it never connects to SQL Server; all checks evaluate pasted facts or capture-script output.
- TDE certificates and the full DMK/SMK key hierarchy are
sqlencryption-review's domain; J13/J14 cover only the migration-script-sequencing risk, not the encryption posture itself. - Dispatched here from
/sqlmigration-reviewfor the security-object family — not invoked standalone for non-migration security review (usesqlencryption-reviewfor that).
Companion Skills
sqlmigration-review— parent skill; version/edition/platform compatibility (Y1–Y15)sqlmigration-objects-review— operational objects (Agent jobs, linked servers, Database Mail) for the rest of the proxy/linked-server definition beyond the stored login (J11/J12)sqlencryption-review— TDE, full DMK/SMK key hierarchy, Always Encrypted, CLEsqlspn-review— SPN/Kerberos delegation for the renamed/relocated instance