DBA Scripts: Get Sysadmin Members

🔧Part of the DBA-Tools Project, copy/paste SQL Server scripts and health checks.In: Security

Identify SQL Server Logins With Sysadmin Access

The sysadmin fixed server role provides unrestricted access to a SQL Server instance.

Members of this role can perform any operation on the server, including creating databases, changing security settings, accessing all data, and modifying server configuration. Because of this level of privilege, knowing exactly who has sysadmin access is a basic but important security review.

In many environments, sysadmin membership grows over time. Temporary access becomes permanent, old administrator accounts remain enabled, service accounts are granted excessive permissions, or accounts from previous teams are never removed.

Regularly reviewing sysadmin membership helps ensure privileged access is intentional and still required.

This script returns all members of the SQL Server sysadmin fixed server role, including account type, disabled status, and account creation details. A clean sysadmin list should never contain surprises. If you don’t recognise every account, you have something to investigate.


Why Sysadmin Members Matters

SQL Server security is built around controlling who can perform privileged actions.

The sysadmin role bypasses normal permission checks and effectively provides full control of the SQL Server instance.

Reviewing sysadmin membership helps with:

  • Security audits.
  • Access reviews.
  • Least privilege assessments.
  • Compliance checks.
  • New environment handovers.
  • Investigating unexpected administrative activity.
  • Identifying stale or unnecessary privileged accounts.

Things I typically look for:

  • Unexpected user accounts with sysadmin access.
  • Disabled accounts that should be removed.
  • Personal accounts used where groups should exist.
  • Service accounts with excessive permissions.
  • Old administrator access from previous teams or projects.

A healthy production environment should have a small, understood list of sysadmin members, with every account having a clear reason for requiring that level of access.

Unlike database permissions, sysadmin bypasses almost every security boundary inside SQL Server. Membership grants unrestricted administrative privilege within the instance, which makes this one of the highest value security checks any DBA can perform.


When to Run This Script

Run this script during:

  • Routine SQL Server security reviews.
  • New server onboarding.
  • Access audits.
  • Compliance assessments.
  • Team or ownership changes.
  • After security incidents.
  • Before production go-lives.
  • Regular DBA health checks.

The Script

Run the following script against your SQL Server instance.

/*
Script Name : Get-SysadminMembers
Category    : security-and-permissions
Purpose     : List members of the sysadmin fixed server role for audits and privilege review.
Author      : Peter Whyte (https://sqldba.blog/dba-scripts-get-sysadmin-members/)
Requires    : VIEW ANY DEFINITION (sysadmin and securityadmin have it implicitly)
HealthCheck : Yes
*/

-- SAFE:ReadOnly
-- IMPACT:Low

SET NOCOUNT ON;

SELECT
    sp.name AS login_name,
    sp.type_desc,
    sp.is_disabled,
    sp.create_date,
    sp.modify_date
FROM sys.server_principals sp
JOIN sys.server_role_members srm 
    ON sp.principal_id = srm.member_principal_id
JOIN sys.server_principals sr 
    ON srm.role_principal_id = sr.principal_id
WHERE sr.name = 'sysadmin'
ORDER BY sp.name;

This joins sys.server_principals with sys.server_role_members to return every login assigned to the sysadmin fixed server role, together with its login type, disabled status and creation metadata.


How To Run From The Repo

Clone DBA Tools, initialise the environment and run the script:

# Clone dba-tools repo:
git clone https://github.com/peterwhyte-lgtm/dba-tools

# Initialize environment:
cd dba-tools
.\Initialize-Environment.ps1

# List members of the sysadmin server role:
.\run.ps1 Get-SysadminMembers

# Run against a remote SQL Server:
.\run.ps1 Get-SysadminMembers -ServerInstance SQLSERVER01

This script lives in the repo at:


Example Output

Below is the script run against a test instance. Eleven principals hold sysadmin: five SQL logins, five Windows service accounts created by the SQL Server installer, and sa. Row 4 is the one to notice. DemoDisabledAdmin carries is_disabled = 1 and still holds the role.

SSMS results grid showing Get-SysadminMembers returning 11 members of the SQL Server sysadmin fixed server role, with login_name, type_desc, is_disabled, create_date and modify_date columns. Five are SQL logins and five are Windows service logins, and DemoDisabledAdmin has is_disabled set to 1.
Eleven sysadmin members on a test instance, including one disabled account.

The status bar reads 11 rows, and that number matters more than it looks. A short result is the thing to be suspicious of, for the reason set out below.


Understanding the Results

One row per principal that is a direct member of sysadmin. Five columns, and the last two are more useful than they look.

login_name
The principal that holds sysadmin. In the run above that is five SQL logins, five Windows service accounts and sa.WatchEvery name here should map to a person or a documented service. A name nobody can account for is the finding.
type_desc
Taken straight from sys.server_principals.type_desc and not filtered, so a value you do not recognise is a real value and not a bug.Blind spotA WINDOWS_GROUP row is a group, not a person. Its members never appear here and have to be reviewed in Active Directory.
is_disabled
1 means the login cannot authenticate today. DemoDisabledAdmin above is the example.WatchDisabled is not removed. Re-enabling is one command and the sysadmin membership comes back with it, so review and justify rather than assuming it is harmless.
create_date
When the login was created. Not when it was granted sysadmin, which is a different and usually more interesting date.
modify_date
When the login was last changed. Measured on SQL Server 2025: this does move when server role membership changes, so on a sysadmin member a modify_date well after the create_date is often the moment the role was granted.WatchA recent modify_date on a privileged login is a reasonable thing to ask a question about.

What This Script Does Not Tell You

Read this before using the output as evidence. The query answers one narrow question: which server principals are direct members of sysadmin.

Scope limits
01
It can under-report, and it does so silently
Visibility of sys.server_principals is itself permission controlled. A caller without VIEW ANY DEFINITION sees only the principals it owns and gets a shorter list rather than an error. On my test instance the full list is 11 rows. The identical query run as a plain login with no server level permission returned 1. No warning, just an instance that looks clean. Confirm the result is complete before you trust it:
SELECT IS_SRVROLEMEMBER('sysadmin') AS is_sysadmin,
       HAS_PERMS_BY_NAME(NULL, NULL, 'VIEW ANY DEFINITION') AS can_see_all_principals;
If can_see_all_principals is 0 and you are not a sysadmin, the list is incomplete. VIEW ANY DATABASE is granted to public and does not help here, which is exactly why it is the wrong thing to check for.
02
It does not expand Windows groups
If DOMAIN\DBA-Admins appears, that group holds sysadmin. The query shows the group and never the people inside it. To answer “who actually has sysadmin on this instance” you have to review that group in Active Directory too, and again every time its membership changes.
03
It does not show access earned another way
CONTROL SERVER, ownership chaining, high privilege database roles and impersonation can add up to something close to administrative control without putting a row in this list.
04
It does not tell you whether the access is justified
Or whether it was ever used. That is the review, and it is the part only you can do. The title says sysadmin members, not everyone who can administer this instance, and the difference matters when the output goes to an auditor.

Best Practices

Good SQL Server security hygiene usually means:

  • Keep sysadmin membership as small as practical.
  • Prefer Windows groups over individual administrator accounts.
  • Avoid granting sysadmin to application service accounts.
  • Remove unused privileged accounts.
  • Review access regularly.
  • Document why each sysadmin member exists.
  • Export results periodically as an audit baseline.
  • Treat every new sysadmin member as a change requiring approval.

The goal is not to eliminate sysadmin access. DBAs and operational teams need appropriate administrative access. The goal is ensuring every privileged account is intentional.


Microsoft’s reference covers sys.server_principals and sys.server_role_members in full.


Related Scripts

You may also find these scripts useful:


Frequently Asked Questions

What is the sysadmin role in SQL Server?

sysadmin is a fixed server role that provides unrestricted administrative access to a SQL Server instance. Members can perform any action on the server.

Should application accounts have sysadmin access?

Generally no.

Application accounts should normally have only the permissions required for the application workload.

Why does the script return fewer rows than I expect?

Almost always permissions. Listing every member of sysadmin needs VIEW ANY DEFINITION, which sysadmin and securityadmin hold implicitly. Without it SQL Server returns only the principals you can see instead of raising an error, so the result looks like a short, healthy list. Run the HAS_PERMS_BY_NAME check above before trusting a small number.

Why don’t I see members of Windows groups?

SQL Server stores only the Windows group as the sysadmin member. Individual users are resolved by Active Directory, so you’ll need to inspect the group’s membership outside SQL Server.

Should every DBA be a sysadmin?

DBAs typically require elevated access, but membership should still be controlled, documented and reviewed regularly.

Is removing sysadmin access enough for security?

No.

Security reviews should also include database permissions, server roles, login activity and authentication settings.


Summary

Reviewing sysadmin membership is one of the simplest SQL Server security checks but one of the most important.

Over time, privileged access can accumulate through temporary requests, migrations, team changes and operational workarounds. Without regular reviews, SQL Server instances can end up with more administrators than intended.

This script provides a quick view of every login with sysadmin access, helping DBAs identify unexpected privileged accounts and maintain better access control.

Run this script regularly, keep historical outputs where appropriate, and investigate every unexpected account. A sysadmin list should never contain surprises.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *