Skip to content

View All Users Permissions on All Databases

A cursor-driven script that audits every permission in every database and shows which roles inherit them.

Published Oct 21, 2009

The server-wide version of the permissions audit. This script walks every database with a cursor, runs a CTE-based permission query in each one via dynamic SQL, and collects the results into a single #Permissions table - including an InheritedFromRole column that traces role-granted permissions back to the individual users who hold them through role membership. Disabled logins are filtered out so you only see what is actually effective.

USE master;

DECLARE @tSQL nVarChar(Max)
DECLARE @Database nVarChar(128)

DECLARE AllDatabases CURSOR FOR
	SELECT
		name
	FROM
		sys.databases
OPEN AllDatabases

CREATE TABLE #Permissions
(
	ServerName sysname null,
	DatabaseName sysname null,
	PrincipalName sysname null,
	PrincipalType sysname null,
	[Class] sysname null,
	ObjectName sysname null,
	PermissionName sysname null,
	PermissionState sysname null,
	InheritedFromRole sysname null
)

FETCH FROM AllDatabases INTO @Database

WHILE(@@FETCH_STATUS = 0)
BEGIN--WHILE

SET @tSQL =
'
USE [' + @Database + '];

WITH CTE AS
(
	SELECT
		USER_NAME(p.grantee_principal_id) AS PrincipalName,
		dp.principal_id,
		dp.type_desc AS PrincipalType,
		p.class_desc,
		CASE p.class_desc
			WHEN ''DATABASE'' THEN DB_NAME(p.major_id)
			WHEN ''SCHEMA'' THEN SCHEMA_NAME(p.major_id)
			WHEN ''OBJECT_OR_COLUMN'' THEN OBJECT_NAME(p.major_id)
			WHEN ''TYPE'' THEN TYPE_NAME(p.major_id)
		ELSE
			''''
		END AS ObjectName,		
		p.permission_name AS PermissionName,
		p.state_desc AS PermissionState
	FROM
		sys.database_permissions AS p
	INNER JOIN sys.database_principals AS dp
		ON p.grantee_principal_id = dp.principal_id
	LEFT OUTER JOIN sys.server_principals as sp
		ON sp.sid = dp.sid
	WHERE
		dp.type_desc = ''DATABASE_ROLE''
		OR (sp.name IS NOT NULL AND sp.is_disabled = 0)
)

INSERT INTO #Permissions
(
	ServerName,
	DatabaseName,
	PrincipalName,
	PrincipalType,
	[Class],
	ObjectName,
	PermissionName,
	PermissionState,
	InheritedFromRole
)

--users
	SELECT
		''' + @@servername + ''',
		db_name(),
		IsNull(p.PrincipalName, ''''),
		IsNull(p.PrincipalType, ''''),
		IsNull(p.class_desc, '''') AS [Class],
		IsNull(p.ObjectName, ''''),
		IsNull(p.PermissionName, ''''),
		IsNull(p.PermissionState, ''''),
		IsNull(cast('''' as sysname), '''') as InheritedFromRole
	FROM
		CTE AS p
	WHERE
		PrincipalType <> ''DATABASE_ROLE''
	UNION
	--role members
	SELECT
		''' + @@servername + ''',
		db_name(),
		IsNull(rm.member_principal_name, ''''),
		IsNull(rm.PrincipalType, ''''),
		IsNull(p.class_desc, ''DATABASE''),
		IsNull(p.ObjectName, IsNull(''<Specific to role: '' + rm.InheritedFromRole + ''>'', '''')),
		IsNull(p.PermissionName, IsNull(''<Specific to role: '' + rm.InheritedFromRole + ''>'', '''')),
		IsNull(p.PermissionName, IsNull(''<Specific to role: '' + rm.InheritedFromRole + ''>'', '''')),
		IsNull(rm.InheritedFromRole, '''')
	FROM
		CTE AS p
	RIGHT OUTER JOIN
		(
			SELECT
				role_principal_id,
				dp.type_desc as PrincipalType,
				rm.member_principal_id,
				user_name(rm.member_principal_id) as member_principal_name,
				user_name(rm.role_principal_id) as InheritedFromRole
			FROM
				sys.database_role_members AS rm
			INNER JOIN sys.database_principals AS dp
				ON rm.member_principal_id = dp.principal_id
		) AS rm
	ON rm.role_principal_id = p.principal_id
order by
	IsNull(p.PrincipalName, '''')
'

EXEC(@tSQL)

FETCH FROM AllDatabases INTO @Database
END--WHILE

CLOSE AllDatabases DEALLOCATE AllDatabases

SELECT * FROM #Permissions

DROP TABLE #Permissions
An unhandled error has occurred. Reload 🗙