Quick Scan Report – Database Ownership
What this check looks for
Two ownership conditions, reported together:
- The owner does not resolve to a login.
SUSER_SNAME(owner_sid)returns null, usually because the person who created the database has left and their account was deleted. - The owner is a member of
sysadmin. Which is very common, and is the one with the security consequence.
This page also covers issue 71, SSISDB not owned by sa, which is the same question applied to the Integration Services catalog.
The check is skipped on Amazon RDS. Note that it deliberately limits how often it calls SUSER_SNAME and IS_SRVROLEMEMBER, because on an instance with slow Active Directory those calls are slow.
Why it matters
The two conditions are different problems and the second is the serious one.
An unresolved owner breaks things quietly: cross database ownership chaining, TRUSTWORTHY behaviour, change data capture, Service Broker, and dbo mapping inside the database. None of it produces an error mentioning ownership. That case is covered in its own right by the database with no owner check.
An owner who is a sysadmin is a privilege escalation path, and specifically so when the database is also TRUSTWORTHY. The combination means:
- The database is marked
TRUSTWORTHY, so code inside it is trusted outside it. - The database owner is a
sysadmin. - Therefore code running as
dboin that database can be made to act withsysadminrights on the whole instance.
Anyone who can create a stored procedure in that database, or anyone who compromises an application account with db_owner, can escalate to full control of the server. It is one of the best known escalation routes in SQL Server, it requires no exploit, and it is entirely a configuration mistake.
TRUSTWORTHY on its own is not the problem, and a sysadmin owner on its own is not the problem. Together they are. Which is why this check reports the ownership half: it is the half you can fix without breaking the feature that needed TRUSTWORTHY.
Restored databases are a common source. Restoring a database carries its owner SID with it, so a database restored from another instance often ends up owned by whoever restored it, who is usually a sysadmin.
How to confirm it yourself
SELECT d.[name],
SUSER_SNAME(d.[owner_sid]) AS [owner],
d.[is_trustworthy_on],
d.[is_db_chaining_on],
CASE WHEN SUSER_SNAME(d.[owner_sid]) IS NULL THEN 'owner does not resolve'
WHEN IS_SRVROLEMEMBER('sysadmin', SUSER_SNAME(d.[owner_sid])) = 1 THEN 'owner is sysadmin'
ELSE 'ok' END AS [finding]
FROM sys.databases AS d WITH (NOLOCK)
ORDER BY [finding], d.[name];
The dangerous combination, on its own:
SELECT [name], SUSER_SNAME([owner_sid]) AS [owner], [is_trustworthy_on]
FROM sys.databases WITH (NOLOCK)
WHERE [is_trustworthy_on] = 1
AND [database_id] > 4
AND IS_SRVROLEMEMBER('sysadmin', SUSER_SNAME([owner_sid])) = 1;
Any row from that query is worth acting on today.
How to fix it
Deal with TRUSTWORTHY first where both are true, because it is usually the one that should not be there at all:
ALTER DATABASE [YourDatabase] SET TRUSTWORTHY OFF;
Most databases with TRUSTWORTHY on do not need it. It gets set to make an unsigned CLR assembly work, or to let a procedure reach outside the database, and both have better answers: signing the assembly with a certificate, or using EXECUTE AS with a specific certificate based login. If turning it off breaks something, that tells you which feature depends on it and the fix is to sign the module properly rather than to trust the whole database.
Then set a sensible owner:
USE [YourDatabase];
GO
ALTER AUTHORIZATION ON DATABASE::[YourDatabase] TO [sa];
sa is the conventional answer: it always exists, it is not deleted when somebody leaves, and it grants the database nothing it did not already have. It works even when sa is disabled or renamed, which is a good practice in its own right.
Where TRUSTWORTHY genuinely has to stay on, do not use sa or any other sysadmin. Create a low privileged login purely to own that database:
CREATE LOGIN [DbOwner_YourDatabase] WITH PASSWORD = 'a strong password', CHECK_POLICY = ON;
ALTER LOGIN [DbOwner_YourDatabase] DISABLE; -- it never needs to log in
ALTER AUTHORIZATION ON DATABASE::[YourDatabase] TO [DbOwner_YourDatabase];
A disabled login can own a database perfectly well, and it closes the escalation path while leaving the feature working.
Then stop it recurring. Set ownership as part of your restore and deployment runbooks, so a database restored by a sysadmin does not silently end up owned by one.
How long it takes
About two hours across an instance, most of it establishing whether any TRUSTWORTHY database genuinely needs it.
Related reports
| Report | Why you would go there |
|---|---|
| Security Posture | Ownership alongside the rest of the security surface. |
| Database Overview | Owner and options for every database. |
| Logins | Which logins exist and which are sysadmin. |
| master Server Permissions | Server level grants that compound this. |
| Restore History | Whether a restore is how the ownership got this way. |
| Orphan Users | The database user side of the same disappearances. |
Related checks
| Check | |
|---|---|
| Database with no owner | The unresolved owner case on its own terms. |
| SSISDB not owned by sa | The same question for the SSIS catalog. |
| Orphan database users | Users left behind by the same deleted logins. |
| Database Connections As SA | Applications connecting with far too much privilege. |
| SQL logins with blank passwords or policy turned off | The accounts an attacker would use to reach this. |
Frequently asked questions
Everything works. Why change it? The unresolved case is a latent fault that surfaces at migration. The sysadmin plus TRUSTWORTHY case is a live security hole rather than a latent one.
Is sa really the right owner? For most databases, yes: it always exists and it survives people leaving. The exception is a TRUSTWORTHY database, where any sysadmin owner is the problem.
Can I change the owner while users are connected? Yes. ALTER AUTHORIZATION is a metadata change and does not need exclusive access.
Why does the check mention Active Directory being slow? Because SUSER_SNAME and IS_SRVROLEMEMBER resolve Windows principals, and on an instance with a slow or unreachable domain controller those calls are slow. The check limits how many it makes for that reason.