Resources Blog

SQL Server database ownership: a complete DBA SQL Server guide for 2019 and beyond

· Fortified Data

Managing database ownership is a critical task for any database administrator (DBA), especially in enterprise environments spanning multiple versions of SQL Server, including SQL Server 2019. This SQL Server guide is designed to help you not only understand but also effectively query, audit, and optimize database ownership, including how to get all databases and owners group name, for enhanced security, compliance, and operational efficiency.

Why Database Ownership Management is Mission-Critical

Database ownership is more than just a technical detail; it’s a cornerstone of data security and governance. The owner of a database holds ultimate administrative control, which means mismanaging ownership can introduce significant risks.

  • Security and Access Control: Unclear ownership can lead to a violation of the principle of least privilege. Orphaned accounts or generic service accounts as owners can create backdoors and unintended privilege escalation paths, making it difficult to track who made what changes.
  • Change Management and Accountability: Knowing the database owner is essential for identifying the right stakeholders to contact before making changes. This ensures proper approval workflows, preventing unauthorized modifications and establishing clear accountability for data quality and availability.
  • Operational Efficiency: In the event of a performance issue or error, knowing the owner helps DBAs quickly get the business context they need to prioritize and troubleshoot problems, leading to faster resolution.
  • Compliance and Regulatory Requirements: Many regulatory frameworks, such as GDPR and HIPAA, require clear data ownership and stewardship documentation for auditing purposes.

Understanding SQL Server Database Ownership Architecture

Each database has an owner, which is typically a login or user. This owner might also be part of a Windows group or SQL Server role. The owner has complete control over the database and can perform any operation within it.

The queries and scripts provided in this SQL Server guide are designed to be compatible across various versions, including SQL Server 2019 and newer, with specific enhancements noted for more recent releases.

Method 1: Basic Database Ownership Query (All SQL Server Versions)

This fundamental query is the simplest way to retrieve ownership information. It combines the sys.databases and sys.server_principals catalog views to provide a list of databases and their owners.

SQL

-- Compatible with SQL Server 2022, 2019, 2017, 2016, and earlier SELECT d.name AS DatabaseName, d.database_id, d.create_date, sp.name AS OwnerName, sp.type_desc AS OwnerType, CASE WHEN sp.name IS NULL THEN 'ORPHANED - Security Risk!' WHEN sp.is_disabled = 1 THEN 'DISABLED OWNER - Review Required' ELSE 'Active' END AS OwnershipStatus, d.collation_name, d.state_desc AS DatabaseState, -- SQL Server version information (available in all versions) CASE WHEN @@VERSION LIKE '%2022%' THEN 'SQL Server 2022' WHEN @@VERSION LIKE '%2019%' THEN 'SQL Server 2019' WHEN @@VERSION LIKE '%2017%' THEN 'SQL Server 2017' WHEN @@VERSION LIKE '%2016%' THEN 'SQL Server 2016' ELSE 'Earlier SQL Server Version' END AS SQLServerVersion FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid ORDER BY CASE WHEN sp.name IS NULL THEN 0 ELSE 1 END, -- Orphaned databases first d.name;

This query not only lists the owner but also flags potential security issues by identifying orphaned or disabled accounts.

Method 2: Comprehensive Ownership Analysis with Windows Group Information

For a more detailed security analysis, this query helps you to get all databases and owners group name information, which is crucial for production environments. It provides a more in-depth view of ownership and associated risks.

SQL

-- Optimized for SQL Server 2022 but compatible with 2019, 2017, 2016+ WITH DatabaseOwners AS ( SELECT d.name AS DatabaseName, d.database_id, d.create_date, sp.name AS OwnerName, sp.type_desc AS OwnerType, sp.is_disabled, sp.create_date AS OwnerCreateDate, d.state_desc AS DatabaseState, d.collation_name, d.compatibility_level, -- Security analysis flags CASE WHEN sp.name IS NULL THEN 'CRITICAL: Orphaned Owner' WHEN sp.is_disabled = 1 THEN 'HIGH: Disabled Owner' WHEN sp.type_desc = 'WINDOWS_LOGIN' AND sp.name LIKE '%service%' THEN 'MEDIUM: Service Account Owner' WHEN sp.type_desc = 'SQL_LOGIN' AND sp.name = 'sa' THEN 'MEDIUM: SA Account Owner' ELSE 'LOW: Standard Owner' END AS SecurityRiskLevel, -- SQL Server 2022+ features (NULL in earlier versions) CASE WHEN EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID('sys.databases') AND name = 'is_ledger') THEN (SELECT CAST(is_ledger AS BIT) FROM sys.databases WHERE name = d.name) ELSE NULL END AS IsLedgerDatabase, d.is_query_store_on AS QueryStoreEnabled FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid ), GroupMembership AS ( SELECT p.name AS PrincipalName, r.name AS GroupName, r.type_desc AS GroupType, p.default_database_name, p.default_language_name, -- Group membership analysis CASE WHEN r.name IN ('sysadmin', 'serveradmin') THEN 'HIGH PRIVILEGE' WHEN r.name LIKE '%admin%' THEN 'ADMINISTRATIVE' ELSE 'STANDARD' END AS PrivilegeLevel FROM sys.server_principals p INNER JOIN sys.server_role_members rm ON p.principal_id = rm.member_principal_id INNER JOIN sys.server_principals r ON rm.role_principal_id = r.principal_id WHERE r.type IN ('R', 'G') -- Server roles and Windows groups ) SELECT do.DatabaseName, do.OwnerName, do.OwnerType, do.SecurityRiskLevel, ISNULL(gm.GroupName, 'No group membership') AS GroupName, ISNULL(gm.GroupType, 'N/A') AS GroupType, ISNULL(gm.PrivilegeLevel, 'UNKNOWN') AS PrivilegeLevel, do.DatabaseState, do.create_date AS DatabaseCreated, do.OwnerCreateDate, do.is_disabled AS OwnerDisabled, do.compatibility_level AS CompatibilityLevel, -- SQL Server version-specific features ISNULL(CAST(do.IsLedgerDatabase AS VARCHAR(10)), 'N/A') AS LedgerDB, ISNULL(CAST(do.QueryStoreEnabled AS VARCHAR(10)), 'N/A') AS QueryStore, gm.default_database_name AS OwnerDefaultDB, -- Business impact assessment CASE WHEN do.DatabaseName IN ('master', 'model', 'msdb') THEN 'SYSTEM - Critical' WHEN do.DatabaseState != 'ONLINE' THEN 'OFFLINE - Review Required' WHEN do.SecurityRiskLevel LIKE 'CRITICAL%' THEN 'HIGH BUSINESS RISK' WHEN do.SecurityRiskLevel LIKE 'HIGH%' THEN 'MODERATE BUSINESS RISK' ELSE 'STANDARD' END AS BusinessImpactLevel FROM DatabaseOwners do LEFT JOIN GroupMembership gm ON do.OwnerName = gm.PrincipalName ORDER BY CASE do.SecurityRiskLevel WHEN 'CRITICAL: Orphaned Owner' THEN 1 WHEN 'HIGH: Disabled Owner' THEN 2 ELSE 3 END, do.DatabaseName, gm.GroupName;

Method 3: PowerShell Automation for Enterprise Environments

For large-scale environments with multiple SQL Server instances, using PowerShell provides a robust way to automate ownership audits and generate comprehensive reports. The script below can be adapted to your environment.

PowerShell

# Import SQL Server module (works with SQL Server 2022, 2019, 2017, 2016+) Import-Module SqlServer -Force

# Define servers to audit (modify for your environment) $ServerInstances = @("Server1", "Server2Instance1", "Server3") $Results = @()

# Enhanced query for comprehensive ownership analysis $Query = @" SELECT @@SERVERNAME AS ServerName, d.name AS DatabaseName, sp.name AS OwnerName, sp.type_desc AS OwnerType, sp.is_disabled AS OwnerDisabled, d.state_desc AS DatabaseState, d.create_date AS DatabaseCreated, d.compatibility_level, -- Risk assessment CASE WHEN sp.name IS NULL THEN 'CRITICAL: Orphaned Owner' WHEN sp.is_disabled = 1 THEN 'HIGH: Disabled Owner' WHEN sp.name = 'sa' THEN 'MEDIUM: SA Owner' ELSE 'LOW: Standard' END AS RiskLevel, -- Version detection for feature availability CASE WHEN d.compatibility_level >= 160 THEN 'SQL Server 2022+' WHEN d.compatibility_level >= 150 THEN 'SQL Server 2019' WHEN d.compatibility_level >= 140 THEN 'SQL Server 2017' WHEN d.compatibility_level >= 130 THEN 'SQL Server 2016' ELSE 'Earlier Version' END AS CompatibilityVersion, -- Business categorization CASE WHEN d.name IN ('master', 'model', 'msdb') THEN 'System' WHEN d.name LIKE '%test%' OR d.name LIKE '%dev%' THEN 'Development' WHEN d.name LIKE '%prod%' OR d.name LIKE '%production%' THEN 'Production' ELSE 'Unknown' END AS DatabaseCategory FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE d.name NOT IN ('tempdb') -- Exclude tempdb as it's recreated on restart ORDER BY CASE WHEN sp.name IS NULL THEN 1 WHEN sp.is_disabled = 1 THEN 2 ELSE 3 END, d.name "@

# Execute across all servers with comprehensive error handling foreach ($Server in $ServerInstances) { try { Write-Host "Auditing database ownership on $Server..." -ForegroundColor Yellow $ServerResults = Invoke-Sqlcmd -ServerInstance $Server -Database "master" -Query $Query -ErrorAction Stop -QueryTimeout 30 $Results += $ServerResults Write-Host "Successfully audited $($ServerResults.Count) databases on $Server" -ForegroundColor Green } catch { Write-Error "Failed to audit $Server`: $($.Exception.Message)" # Log failed server for manual review $FailedServer = [PSCustomObject]@{ ServerName = $Server DatabaseName = "CONNECTION_FAILED" OwnerName = $.Exception.Message RiskLevel = "CRITICAL: Audit Failed" DatabaseCategory = "Unknown" } $Results += $FailedServer } }

# Generate comprehensive report Write-Host "`n=== DATABASE OWNERSHIP AUDIT SUMMARY ===" -ForegroundColor Cyan Write-Host "Total Databases Audited: $($Results.Count)" -ForegroundColor White

# Security risk analysis $CriticalIssues = $Results | Where-Object { $.RiskLevel -like "CRITICAL*" } $HighRiskIssues = $Results | Where-Object { $.RiskLevel -like "HIGH*" }

Write-Host "Critical Issues (Immediate Action Required): $($CriticalIssues.Count)" -ForegroundColor Red Write-Host "High Risk Issues (Review Required): $($HighRiskIssues.Count)" -ForegroundColor Yellow

# Display critical issues for immediate attention if ($CriticalIssues.Count -gt 0) { Write-Host "`nCRITICAL ISSUES REQUIRING IMMEDIATE ATTENTION:" -ForegroundColor Red $CriticalIssues | Format-Table ServerName, DatabaseName, RiskLevel -AutoSize }

# Export comprehensive results with timestamp $ExportPath = "DatabaseOwnership_Audit_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" $Results | Export-Csv -Path $ExportPath -NoTypeInformation Write-Host "`nComplete audit results exported to: $ExportPath" -ForegroundColor Green

# Generate executive summary for management reporting $ExecutiveSummary = @" DATABASE OWNERSHIP AUDIT EXECUTIVE SUMMARY Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')

OVERALL STATISTICS: - Total Databases: $($Results.Count) - Critical Issues: $($CriticalIssues.Count) - High Risk Issues: $($HighRiskIssues.Count) - Servers Audited: $($ServerInstances.Count)

IMMEDIATE ACTION ITEMS: $(if ($CriticalIssues.Count -gt 0) { "- $($CriticalIssues.Count) databases have orphaned or failed owners requiring immediate remediation" } else { "- No critical ownership issues identified" }) $(if ($HighRiskIssues.Count -gt 0) { "- $($HighRiskIssues.Count) databases have disabled owners requiring review" } else { "- No high-risk ownership issues identified" })

BUSINESS IMPACT: $(if (($CriticalIssues.Count + $HighRiskIssues.Count) -gt 0) { "- Ownership issues may impact security, compliance, and business continuity" } else { "- Database ownership structure appears healthy" }) $(if ($Results | Where-Object { $.DatabaseCategory -eq "Production" -and $.RiskLevel -notlike "LOW*" }) { "- Production databases have ownership issues requiring priority attention" } else { "- Production database ownership appears properly managed" }) "@

$ExecutiveSummary | Out-File -FilePath "DatabaseOwnership_ExecutiveSummary_$(Get-Date -Format 'yyyyMMdd').txt" Write-Host "Executive summary generated for management reporting" -ForegroundColor Green

Method 4: Advanced Cross-Version Role Analysis for Security Audits

This advanced method is a comprehensive way to analyze database-level roles, which is essential for security audits and compliance reporting across all SQL Server versions. It goes beyond simple ownership and provides detailed role membership information.

SQL

-- Advanced cross-version database ownership and role analysis DECLARE @sql NVARCHAR(MAX) = '' DECLARE @DatabaseName NVARCHAR(128) DECLARE @SQLVersion VARCHAR(50) DECLARE @TotalDatabases INT = 0 DECLARE @ProcessedDatabases INT = 0

-- Enhanced version detection for optimization and feature availability SET @SQLVersion = CASE WHEN @@VERSION LIKE '%2022%' THEN '2022' WHEN @@VERSION LIKE '%2019%' THEN '2019' WHEN @@VERSION LIKE '%2017%' THEN '2017' WHEN @@VERSION LIKE '%2016%' THEN '2016' ELSE 'LEGACY' END

PRINT 'Starting comprehensive database ownership analysis on SQL Server ' + @SQLVersion PRINT 'Analysis timestamp: ' + CONVERT(VARCHAR, GETDATE(), 120)

-- Create comprehensive results table CREATE TABLE #DatabaseRoleAnalysis ( ServerName NVARCHAR(128), DatabaseName NVARCHAR(128), DatabaseOwner NVARCHAR(128), OwnerType NVARCHAR(128), OwnerStatus NVARCHAR(128), RoleName NVARCHAR(128), MemberName NVARCHAR(128), MemberType NVARCHAR(128), SQLServerVersion VARCHAR(50), CompatibilityLevel TINYINT, DatabaseState NVARCHAR(128), SecurityRiskLevel NVARCHAR(128), BusinessCategory NVARCHAR(128), -- Version-specific columns IsQueryStoreOn BIT, IsLedgerDB BIT, AuditTimestamp DATETIME2 )

-- Get total database count for progress tracking SELECT @TotalDatabases = COUNT(*) FROM sys.databases WHERE state = 0 AND name NOT IN ('tempdb')

PRINT 'Analyzing ' + CAST(@TotalDatabases AS VARCHAR) + ' databases...'

-- Enhanced cursor for comprehensive database analysis DECLARE db_cursor CURSOR FOR SELECT d.name, sp.name AS OwnerName, sp.type_desc AS OwnerType, CASE WHEN sp.name IS NULL THEN 'CRITICAL: Orphaned' WHEN sp.is_disabled = 1 THEN 'HIGH: Disabled' WHEN sp.name = 'sa' THEN 'MEDIUM: SA Account' ELSE 'LOW: Standard' END AS SecurityRisk, CASE WHEN d.name IN ('master', 'model', 'msdb') THEN 'System' WHEN d.name LIKE '%test%' OR d.name LIKE '%dev%' THEN 'Development' WHEN d.name LIKE '%prod%' OR d.name LIKE '%production%' THEN 'Production' ELSE 'Business' END AS BusinessCategory FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE d.state = 0 -- Only online databases AND d.name NOT IN ('tempdb') -- Exclude tempdb

OPEN db_cursor FETCH NEXT FROM db_cursor INTO @DatabaseName, @OwnerName, @OwnerType, @SecurityRisk, @BusinessCategory

WHILE @@FETCH_STATUS = 0 BEGIN SET @ProcessedDatabases = @ProcessedDatabases + 1

-- Progress indicator for long-running analyses IF @ProcessedDatabases % 10 = 0 PRINT 'Progress: ' + CAST(@ProcessedDatabases AS VARCHAR) + '/' + CAST(@TotalDatabases AS VARCHAR) + ' databases processed...'

-- Build comprehensive dynamic SQL with version-specific optimizations SET @sql = N' USE [' + @DatabaseName + N']

INSERT INTO #DatabaseRoleAnalysis SELECT @@SERVERNAME AS ServerName, ''' + @DatabaseName + N''' AS DatabaseName, ''' + ISNULL(@OwnerName, 'ORPHANED_OWNER') + N''' AS DatabaseOwner, ''' + ISNULL(@OwnerType, 'UNKNOWN') + N''' AS OwnerType, CASE WHEN ''' + ISNULL(@OwnerName, 'NULL') + N''' IS NULL THEN ''Orphaned - Security Risk'' WHEN EXISTS (SELECT 1 FROM sys.server_principals WHERE name = ''' + ISNULL(@OwnerName, '') + N''' AND is_disabled = 1) THEN ''Disabled - Review Required'' ELSE ''Active'' END AS OwnerStatus, r.name AS RoleName, ISNULL(m.name, ''No members assigned'') AS MemberName, ISNULL(m.type_desc, ''N/A'') AS MemberType, ''' + @SQLVersion + N''' AS SQLServerVersion, (SELECT compatibility_level FROM sys.databases WHERE name = ''' + @DatabaseName + N''') AS CompatibilityLevel, (SELECT state_desc FROM sys.databases WHERE name = ''' + @DatabaseName + N''') AS DatabaseState, ''' + @SecurityRisk + N''' AS SecurityRiskLevel, ''' + @BusinessCategory + N''' AS BusinessCategory,'

-- Add version-specific feature detection IF @SQLVersion IN ('2019', '2022') SET @sql = @sql + N' (SELECT ISNULL(is_query_store_on, 0) FROM sys.databases WHERE name = ''' + @DatabaseName + N''') AS IsQueryStoreOn,' ELSE SET @sql = @sql + N' NULL AS IsQueryStoreOn,'

-- SQL Server 2022 specific features IF @SQLVersion = '2022' SET @sql = @sql + N' (SELECT ISNULL(CASE WHEN EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(''sys.databases'') AND name = ''is_ledger'') THEN is_ledger ELSE 0 END, 0) FROM sys.databases WHERE name = ''' + @DatabaseName + N''') AS IsLedgerDB,' ELSE SET @sql = @sql + N' NULL AS IsLedgerDB,'

SET @sql = @sql + N' GETDATE() AS AuditTimestamp FROM sys.database_role_members rm RIGHT JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id LEFT JOIN sys.database_principals m ON rm.member_principal_id = m.principal_id WHERE r.type = ''R'' AND r.name IN (''db_owner'', ''db_datareader'', ''db_datawriter'', ''db_ddladmin'', ''db_securityadmin'', ''db_accessadmin'', ''db_backupoperator'', ''db_denydatareader'', ''db_denydatawriter'') '

-- Execute with error handling BEGIN TRY EXEC sp_executesql @sql END TRY BEGIN CATCH -- Log databases that couldn't be analyzed INSERT INTO #DatabaseRoleAnalysis (ServerName, DatabaseName, DatabaseOwner, SecurityRiskLevel, BusinessCategory, AuditTimestamp) VALUES (@@SERVERNAME, @DatabaseName, 'ANALYSIS_FAILED', 'CRITICAL: Could not analyze', @BusinessCategory, GETDATE())

PRINT 'Warning: Could not analyze database ' + @DatabaseName + ' - ' + ERROR_MESSAGE() END CATCH

FETCH NEXT FROM db_cursor INTO @DatabaseName, @OwnerName, @OwnerType, @SecurityRisk, @BusinessCategory END

CLOSE db_cursor DEALLOCATE db_cursor

PRINT 'Analysis complete. Generating comprehensive report...'

-- Generate executive summary statistics DECLARE @TotalRecords INT, @CriticalIssues INT, @HighRiskIssues INT, @ProductionDBsAtRisk INT

SELECT @TotalRecords = COUNT(*) FROM #DatabaseRoleAnalysis SELECT @CriticalIssues = COUNT(DISTINCT DatabaseName) FROM #DatabaseRoleAnalysis WHERE SecurityRiskLevel LIKE 'CRITICAL%' SELECT @HighRiskIssues = COUNT(DISTINCT DatabaseName) FROM #DatabaseRoleAnalysis WHERE SecurityRiskLevel LIKE 'HIGH%' SELECT @ProductionDBsAtRisk = COUNT(DISTINCT DatabaseName) FROM #DatabaseRoleAnalysis WHERE BusinessCategory = 'Production' AND SecurityRiskLevel NOT LIKE 'LOW%'

-- Display comprehensive results with business context SELECT ServerName, DatabaseName, DatabaseOwner, OwnerType, OwnerStatus, SecurityRiskLevel, BusinessCategory, RoleName, MemberName, MemberType, SQLServerVersion, CompatibilityLevel, DatabaseState, CASE WHEN IsQueryStoreOn = 1 THEN 'Enabled' WHEN IsQueryStoreOn = 0 THEN 'Disabled' ELSE 'N/A (Version < 2019)' END AS QueryStoreStatus, CASE WHEN IsLedgerDB = 1 THEN 'Yes - Enhanced Security Required' WHEN IsLedgerDB = 0 THEN 'No' ELSE 'N/A (Version < 2022)' END AS LedgerDatabase, AuditTimestamp, -- Business impact assessment CASE WHEN BusinessCategory = 'Production' AND SecurityRiskLevel LIKE 'CRITICAL%' THEN 'IMMEDIATE BUSINESS RISK' WHEN BusinessCategory = 'Production' AND SecurityRiskLevel LIKE 'HIGH%' THEN 'ELEVATED BUSINESS RISK' WHEN BusinessCategory = 'System' AND SecurityRiskLevel NOT LIKE 'LOW%' THEN 'SYSTEM SECURITY RISK' ELSE 'STANDARD MONITORING' END AS BusinessImpactLevel FROM #DatabaseRoleAnalysis ORDER BY CASE SecurityRiskLevel WHEN 'CRITICAL: Orphaned' THEN 1 WHEN 'CRITICAL: Could not analyze' THEN 2 WHEN 'HIGH: Disabled' THEN 3 ELSE 4 END, CASE BusinessCategory WHEN 'Production' THEN 1 WHEN 'System' THEN 2 ELSE 3 END, DatabaseName, RoleName, MemberName

-- Executive Summary Report PRINT '' PRINT '=== EXECUTIVE SUMMARY ===' PRINT 'Analysis completed at: ' + CONVERT(VARCHAR, GETDATE(), 120) PRINT 'SQL Server Version: ' + @SQLVersion PRINT 'Total Database Role Assignments: ' + CAST(@TotalRecords AS VARCHAR) PRINT 'Databases with Critical Issues: ' + CAST(@CriticalIssues AS VARCHAR) PRINT 'Databases with High Risk Issues: ' + CAST(@HighRiskIssues AS VARCHAR) PRINT 'Production Databases at Risk: ' + CAST(@ProductionDBsAtRisk AS VARCHAR)

IF @CriticalIssues > 0 OR @ProductionDBsAtRisk > 0 PRINT 'RECOMMENDATION: Immediate action required for security and business continuity' ELSE PRINT 'STATUS: Database ownership structure appears healthy'

-- Clean up DROP TABLE #DatabaseRoleAnalysis

PRINT 'Database ownership analysis completed successfully.'

SQL Server 2022 Specific Features and Security Considerations

Ledger Database Ownership Management

SQL Server 2022 introduced Ledger databases for tamper-evident data storage. These databases have special ownership considerations due to their enhanced security.

SQL

-- SQL Server 2022: Comprehensive Ledger database ownership analysis SELECT d.name AS DatabaseName, sp.name AS OwnerName, sp.type_desc AS OwnerType, d.is_ledger AS IsLedgerDatabase, d.is_query_store_on AS QueryStoreEnabled, d.create_date, -- Ledger-specific security recommendations CASE WHEN d.is_ledger = 1 AND sp.type_desc != 'SQL_LOGIN' THEN 'RECOMMENDATION: Consider SQL Login for Ledger DB' WHEN d.is_ledger = 1 AND sp.name = 'sa' THEN 'CAUTION: SA ownership may complicate audit trails' WHEN d.is_ledger = 1 THEN 'OK: Appropriate ownership for Ledger database' ELSE 'N/A: Standard database' END AS LedgerOwnershipGuidance, -- Business impact of Ledger ownership CASE WHEN d.is_ledger = 1 THEN 'HIGH: Ownership changes affect tamper-evidence and audit trails' ELSE 'STANDARD: Normal ownership impact' END AS BusinessImpactLevel FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE d.database_id > 4 -- Skip system databases ORDER BY d.is_ledger DESC, d.name;

Enhanced Query Store Integration for Ownership Monitoring

Since SQL Server 2019, Query Store has provided improved performance monitoring. This integration can also be used to track ownership-related query performance.

SQL

-- Monitor Query Store status and ownership correlation (SQL Server 2019+) SELECT d.name AS DatabaseName, sp.name AS OwnerName, d.is_query_store_on AS QueryStoreEnabled, -- Performance monitoring recommendations CASE WHEN d.is_query_store_on = 1 AND sp.is_disabled = 1 THEN 'ALERT: Disabled owner but Query Store active - review monitoring' WHEN d.is_query_store_on = 1 THEN 'OK: Query Store can track ownership-related performance' WHEN d.is_query_store_on = 0 AND d.name NOT LIKE '%test%' THEN 'CONSIDER: Enable Query Store for better monitoring' ELSE 'N/A: Query Store appropriately configured' END AS MonitoringRecommendation, -- Business continuity considerations CASE WHEN d.is_query_store_on = 1 THEN 'Query Store provides performance history for business impact analysis' ELSE 'Limited performance history available for business decisions' END AS BusinessContinuityNotes FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE d.database_id > 4 -- Skip system databases ORDER BY d.is_query_store_on DESC, d.name;

Best Practices for Database Ownership Management

  • Security-First Ownership Strategy: Establish clear policies to avoid shared or generic accounts as database owners. Conduct regular audits and document ownership changes with business justification.
  • Operational Excellence: Plan for cross-version compatibility by testing queries on your oldest SQL Server version first. Use version detection in scripts to ensure they run correctly on different systems.
  • Automated Monitoring and Alerting: Implement automated alerts for ownership changes and schedule regular audits using scripts to quickly identify and address security risks.
  • Compliance and Governance: Maintain current ownership inventories for all databases to meet regulatory compliance requirements. Document accountability chains and have a plan for personnel changes.

Troubleshooting Database Ownership Issues

Identifying and Resolving Orphaned Database Owners

Orphaned owners are a critical security risk. The following query helps identify and assess the business impact of these issues.

SQL

-- Comprehensive orphaned owner detection and impact analysis WITH OrphanedDatabases AS ( SELECT d.name AS DatabaseName, d.owner_sid, d.compatibility_level, d.state_desc AS DatabaseState, d.create_date, -- Business impact assessment CASE WHEN d.name IN ('master', 'model', 'msdb') THEN 'CRITICAL: System Database' WHEN d.name LIKE '%prod%' OR d.name LIKE '%production%' THEN 'HIGH: Production Database' WHEN d.state_desc != 'ONLINE' THEN 'MEDIUM: Offline Database' ELSE 'STANDARD: Business Database' END AS BusinessImpactLevel, -- Version context for remediation planning CASE WHEN d.compatibility_level >= 160 THEN 'SQL Server 2022+' WHEN d.compatibility_level >= 150 THEN 'SQL Server 2019' WHEN d.compatibility_level >= 140 THEN 'SQL Server 2017' WHEN d.compatibility_level >= 130 THEN 'SQL Server 2016' ELSE 'Earlier SQL Server Version' END AS DatabaseVersion FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE sp.name IS NULL AND d.name NOT IN ('master', 'model', 'msdb', 'tempdb') ) SELECT DatabaseName, BusinessImpactLevel, DatabaseVersion, DatabaseState, create_date, 'IMMEDIATE ACTION: Change ownership to valid principal' AS RecommendedAction, -- Suggested remediation script 'ALTER AUTHORIZATION ON DATABASE::[' + DatabaseName + '] TO [sa];' AS RemediationScript FROM OrphanedDatabases ORDER BY CASE BusinessImpactLevel WHEN 'CRITICAL: System Database' THEN 1 WHEN 'HIGH: Production Database' THEN 2 ELSE 3 END, DatabaseName;

Analyzing Disabled Database Owners

Disabled owners can cause operational problems and present a security risk.

SQL

-- Disabled owner analysis with business impact assessment SELECT d.name AS DatabaseName, sp.name AS DisabledOwnerName, sp.create_date AS OwnerCreateDate, sp.modify_date AS OwnerLastModified, d.state_desc AS DatabaseState, -- Business continuity risk assessment CASE WHEN d.state_desc = 'ONLINE' AND sp.is_disabled = 1 THEN 'HIGH: Online database with disabled owner - potential operational risk' WHEN d.state_desc != 'ONLINE' THEN 'MEDIUM: Offline database - lower immediate risk' ELSE 'REVIEW: Standard monitoring required' END AS RiskAssessment, -- Recommended actions based on business impact CASE WHEN d.name LIKE '%prod%' OR d.name LIKE '%production%' THEN 'URGENT: Change production database owner immediately' WHEN d.name LIKE '%test%' OR d.name LIKE '%dev%' THEN 'SCHEDULED: Update during maintenance window' ELSE 'PLANNED: Include in next ownership review cycle' END AS ActionPriority, 'ALTER AUTHORIZATION ON DATABASE::[' + d.name + '] TO [NewOwnerLogin];' AS SuggestedFix FROM sys.databases d INNER JOIN sys.server_principals sp ON d.owner_sid = sp.sid WHERE sp.is_disabled = 1 AND d.name NOT IN ('tempdb') ORDER BY CASE WHEN d.name LIKE '%prod%' OR d.name LIKE '%production%' THEN 1 WHEN d.state_desc = 'ONLINE' THEN 2 ELSE 3 END, d.name;

Version-Specific Ownership Remediation

Different versions of SQL Server may require specific approaches.

SQL

-- Version-aware ownership remediation recommendations DECLARE @SQLVersion VARCHAR(10) SET @SQLVersion = CASE WHEN @@VERSION LIKE '%2022%' THEN '2022' WHEN @@VERSION LIKE '%2019%' THEN '2019' WHEN @@VERSION LIKE '%2017%' THEN '2017' WHEN @@VERSION LIKE '%2016%' THEN '2016' ELSE 'LEGACY' END

SELECT d.name AS DatabaseName, sp.name AS CurrentOwner, sp.type_desc AS OwnerType, @SQLVersion AS SQLServerVersion, -- Version-specific recommendations CASE @SQLVersion WHEN '2022' THEN CASE WHEN EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID('sys.databases') AND name = 'is_ledger') AND (SELECT is_ledger FROM sys.databases WHERE name = d.name) = 1 THEN 'SQL 2022 Ledger DB: Consider dedicated SQL login for enhanced audit trail' ELSE 'SQL 2022: Standard ownership practices apply' END WHEN '2019' THEN 'SQL 2019: Leverage Data Discovery for sensitive database identification' WHEN '2017' THEN 'SQL 2017: Focus on Always Encrypted ownership implications' WHEN '2016' THEN 'SQL 2016: Implement Row-Level Security ownership considerations' ELSE 'Legacy SQL: Focus on basic security hardening' END AS VersionSpecificGuidance, -- Business-focused remediation steps CASE WHEN sp.name IS NULL THEN '1. Identify business owner, 2. Create/assign' ELSE 'Standard remediation for ' + @SQLVersion END AS BusinessRemediationSteps FROM sys.databases d LEFT JOIN sys.server_principals sp ON d.owner_sid = sp.sid ORDER BY d.name;

This article provides a comprehensive SQL Server guide to managing database ownership effectively. By using the provided T-SQL and PowerShell scripts, you can significantly enhance your database security and operational efficiency.

At Fortified Data, we specialize in more than just keeping your databases running — we optimize, protect, and future-proof them. Whether you need SQL Server expertise, performance tuning, or fully managed database services, our team is here to ensure your data environment supports your business goals. Let us help you get the most out of your technology investments.

More on this

All articles

SQL Server upgrades: the secret to success is planning ahead

Ask any Database Administrator about why organizations large and small tend to procrastinate about SQL Server upgrades and you’ll hear similar replies: “upgrades are painful, upgrades are difficult,” “everything breaks.” So instead of going through the process of upgrading, they ignore it until it creates a roadblock.

Read the article

Let us show you what's possible.

Two ways to start