More often than not, while troubleshooting SQL Server Security Issues, you end up performing post-mortem analysis. Under such circumstances, the Ring Buffer output comes in handy because it stores the Security Errors that were reported in the past for a certain period of time.
For an example, let’s say if you tried to create a SQL Login with the Password Policy enabled and provided a password that didn’t match a password policy, then you will receive an error stating that the password is not complex enough. This error will be stored in the ring buffer. When you execute the query below, you will find out the SPID that raised the error along with the API Name that is failing. In the sample output for this scenario described above, you will find that the NetValidatePwdPolicy failed.
If you convert the ErrorCode value 0x8C5 (= 2245) to decimal and do a NET HELPMSG <number> from command prompt, you will find more information on why that error occurred.
Output of NET HELPMSG 2245:
The password does not meet the password policy requirements. Check the minimum password length, password complexity and password history requirements.
The Calling API Name and the API Name are very helpful when troubleshooting Domain Account related security errors as it would call functions related to Directory Services whose documentation can be found on Tech Net which would make your troubleshooting easier.
Sample Output:
Notification_time: 2009-11-06 08:37:08.023 ErrorCode: 0x8C5 CallingAPIName: NetValidatePwdPolicy APIName: NetValidatePwdPolicy SPID: 53 Record Id: 0 Type: RING_BUFFER_SECURITY_ERROR
For SQL Server 2005:
SELECT CONVERT (varchar(30), GETDATE(), 121) as runtime, DATEADD (ms, -1 * ((sys.cpu_ticks / sys.cpu_ticks_in_ms) - a.[Record Time]), GETDATE()) AS Notification_time, a.* , sys.ms_ticks AS [Current Time] FROM (SELECT x.value('(//Record/Error/ErrorCode)[1]', 'varchar(30)') AS [ErrorCode], x.value('(//Record/Error/CallingAPIName)[1]', 'varchar(255)') AS [CallingAPIName], x.value('(//Record/Error/APIName)[1]', 'varchar(255)') AS [APIName], x.value('(//Record/Error/SPID)[1]', 'int') AS [SPID], x.value('(//Record/@id)[1]', 'bigint') AS [Record Id], x.value('(//Record/@type)[1]', 'varchar(30)') AS [Type], x.value('(//Record/@time)[1]', 'bigint') AS [Record Time] FROM (SELECT CAST (record as xml) FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = 'RING_BUFFER_SECURITY_ERROR') AS R(x)) a CROSS JOIN sys.dm_os_sys_info sys ORDER BY a.[Record Time] ASC
For SQL Server 2008
SELECT CONVERT (varchar(30), GETDATE(), 121) as runtime, dateadd (ms, (a.[Record Time] - sys.ms_ticks), GETDATE()) as [Notification_Time], a.* , sys.ms_ticks AS [Current Time] FROM (SELECT x.value('(//Record/Error/ErrorCode)[1]', 'varchar(30)') AS [ErrorCode], x.value('(//Record/Error/CallingAPIName)[1]', 'varchar(255)') AS [CallingAPIName], x.value('(//Record/Error/APIName)[1]', 'varchar(255)') AS [APIName], x.value('(//Record/Error/SPID)[1]', 'int') AS [SPID], x.value('(//Record/@id)[1]', 'bigint') AS [Record Id], x.value('(//Record/@type)[1]', 'varchar(30)') AS [Type], x.value('(//Record/@time)[1]', 'bigint') AS [Record Time] FROM (SELECT CAST (record as xml) FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = 'RING_BUFFER_SECURITY_ERROR') AS R(x)) a CROSS JOIN sys.dm_os_sys_info sys ORDER BY a.[Record Time] ASC
Additional Reference