Monday, August 17, 2026

The SSMS db_owner Checkbox That Wouldn't Behave

V-RodDBA · Troubleshooting

The SSMS db_owner Checkbox That Wouldn't Behave

Same server, same GUI, same new-user wizard — and yet some databases auto-check db_owner on you and some don't. Here's the SID mismatch actually causing it.

A client asked me a version of this question recently: "when creating new SQL users with SSMS, they're getting added to the db_owner role automatically?" My first instinct was to say no — SSMS maps new users to public by default, full stop. That's still true. But if you're staring at the User Mapping screen watching that db_owner box check itself before you've touched anything, something else is going on, and it's not random.

What made this case interesting is that it wasn't happening on every database — just some of them, with no obvious pattern at first glance. Chasing that inconsistency down landed on a root cause that shows up constantly after restores and migrations: a binary SID that never got rewritten. Worth a full write-up, because "it works on some databases and not others" is exactly the kind of bug report that makes DBAs assume they're losing their minds.

A note on using sa: a few examples below reassign ownership to [sa] for simplicity. sa is a built-in account with unrestricted sysadmin rights, so making it a database owner widens your attack surface more than the fix actually requires, and plenty of shops disable it outright for exactly that reason. Follow your organization's security policy for database ownership rather than defaulting to sa.

Ruling Out the Obvious Suspects

Before you go digging into SIDs, check the two things that actually are documented SSMS behavior. First: a database with a blank or invalid owner — usually from a restore or attach where the original creator's login no longer exists — makes the User Mapping GUI glitch and pre-check db_owner for anyone you try to map. The fix is a one-liner:

USE [YourDatabaseName];
GO
ALTER AUTHORIZATION ON DATABASE::[YourDatabaseName] TO [sa];
GO

Second: check the model database. Anything configured there gets inherited by every new database on the instance, db_owner defaults included. If someone made a "helpful" change to model six months ago, this is where it comes back to bite you.

In this case, one orphaned database turned up — fixed, confirmed, done. But the client came back with: other databases were still doing it, and not consistently.

Why It's Inconsistent Even on Databases You Own

Here's where it got genuinely strange. The client owned nearly every database on the instance under their own Windows login — one exception was owned by a disabled sa account. That one behaved fine. The rest, all owned by the same account, split roughly down the middle between "behaves" and "checks the box." Same owner, same login, same SSMS build. Three mechanics explain the split:

1 AD group ownership vs. an individual login. If a database was created or restored under an AD group context (DOMAIN\Domain_DBAs) rather than one person's account, SSMS can't cleanly resolve individual permissions against a group owner and misbehaves.
2 SIDs out of sync between server and database metadata. The owner's display name matches everywhere in the GUI, but the binary SID backing that name doesn't — a leftover from a migration or restore. This turned out to be the actual cause here.
3 Contained database settings. A contained database bypasses the instance-level security architecture entirely, which changes how ownership resolves and can produce the same symptom for unrelated reasons.

The Smoking Gun

Every database triggering the bug traced back to option 2: the database-level dbo user still carried the binary SID from the server it was originally restored or attached from. SSMS shows the correct display name, because it resolves the SID against Active Directory, not against the local instance — but underneath, master.sys.databases.owner_sid and sys.database_principals.sid (for the dbo row) don't agree. The user-mapping logic hits that mismatch and fails open, pre-checking db_owner as a safety default.

You can confirm it across every database on the instance in one pass:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
USE [' + d.name + N'];
SELECT DB_NAME() AS DatabaseName,
       CASE
         WHEN sp.sid IS NULL THEN ''MISSING dbo PRINCIPAL''
         WHEN sl.is_disabled = 1 THEN ''OWNER IS DISABLED''
         WHEN d.owner_sid <> sp.sid THEN ''MISMATCH: Master SID <> Database SID''
         ELSE ''VALID''
       END AS Status,
       d.owner_sid AS MasterSid,
       sp.sid AS DatabaseSid;'
FROM master.sys.databases d
LEFT JOIN sys.server_principals sl ON sl.sid = d.owner_sid
WHERE d.database_id > 4;

EXEC sp_executesql @sql;

Once you've got a list of MISMATCH databases, the fix isn't reassigning ownership once — it's cycling it. Handing ownership to sa clears the stale metadata, and handing it right back rewrites a fresh, correct SID under the current server's context:

USE [YourDatabaseName];
GO
ALTER AUTHORIZATION ON DATABASE::[YourDatabaseName] TO [sa];
GO
ALTER AUTHORIZATION ON DATABASE::[YourDatabaseName] TO [DOMAIN\YourLogin];
GO

Run the validation query again afterward. MISMATCH rows should convert to VALID. Anything still flagged as OWNER IS DISABLED is a database legitimately owned by a disabled sa account — normal in locked-down environments, and not the bug you're chasing.

Reading the Validation Report

Status What It Means
VALID Owner SID matches on both ends. SSMS will behave normally.
MISMATCH The bug. Server and database-level SIDs disagree — usually a leftover from a restore or attach. Cycle ownership through sa to fix.
MISSING dbo PRINCIPAL No valid owner at all. Assign one explicitly with ALTER AUTHORIZATION.
OWNER IS DISABLED Database is owned by a disabled login (often sa). Perfectly legal, and won't trigger the bug.

The practical takeaway: add ALTER AUTHORIZATION ON DATABASE::[DBName] TO [ValidOwner]; to every post-restore and post-migration checklist, right next to the usual orphaned-user cleanup. A stale SID is a lot like a stale timing chain on a bike — it won't announce itself until you're already relying on it, and by then you're troubleshooting under load instead of at your own pace.

V-RodDBA · August 13, 2026

No comments:

Post a Comment