SQL to Check for Long-Running Open Transactions in SQL Server
Published 2026-08-13 · Updated 2026-08-13 · Last Verified 2026-08-13
Answer
You can identify long-running open transactions by joining `sys.dm_tran_active_transactions` with `sys.dm_tran_session_transactions` and sorting by the oldest `transaction_begin_time`. Adding `sys.dm_exec_sessions` also reveals which login and application is responsible. The identification SQL is read-only, but forcibly terminating a session with `KILL` is a high-risk operation that triggers a rollback.
Applicability of This Document
| Product | SQL Server / Amazon RDS for SQL Server / Azure SQL Managed Instance |
|---|---|
| Verified Versions | SQL Server 2008 and later |
| Environment | On-premises, EC2, Amazon RDS, Azure |
| Required Permissions | The read-only SQL requires VIEW SERVER STATE. `DBCC OPENTRAN` requires sysadmin or db_owner. `KILL` requires ALTER ANY CONNECTION (or processadmin / sysadmin) |
| Execution Impact | The read-only SQL makes no changes. `KILL` forcibly terminates a session and rolls back any uncommitted transaction |
| Restart | Not required |
| Last Verified | 2026-08-13 |
Ready-to-Run Commands
- 対象
- SQL Server 2008 and later / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- None (read-only)
- Production実行
- Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
at.transaction_id,
at.name AS transaction_name,
at.transaction_begin_time,
DATEDIFF(SECOND, at.transaction_begin_time, GETDATE()) AS open_seconds,
at.transaction_type, -- 1:読み書き 2:読み取り専用 3:システム 4:分散
at.transaction_state, -- 2:アクティブ 3:終了(読み取り専用) 7:ロールバック中
st.session_id,
st.is_user_transaction,
st.open_transaction_count,
es.login_name,
es.host_name,
es.program_name,
es.status AS session_status,
es.last_request_start_time,
es.last_request_end_time,
ec.client_net_address,
ec.connect_time,
txt.text AS last_statement
FROM sys.dm_tran_active_transactions AS at
INNER JOIN sys.dm_tran_session_transactions AS st
ON at.transaction_id = st.transaction_id
LEFT JOIN sys.dm_exec_sessions AS es
ON st.session_id = es.session_id
LEFT JOIN sys.dm_exec_connections AS ec
ON st.session_id = ec.session_id
OUTER APPLY sys.dm_exec_sql_text(ec.most_recent_sql_handle) AS txt
WHERE st.is_user_transaction = 1
ORDER BY at.transaction_begin_time ASC;Using `CROSS APPLY sys.dm_exec_sql_text(...)` would drop sessions whose handle cannot be retrieved. To avoid missing any abandoned sessions, this uses `OUTER APPLY` instead. A session where `session_status` is sleeping and `open_transaction_count` is 1 or more is the typical "abandoned BEGIN TRAN" pattern.
- 対象
- SQL Server 2008 and later / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- None (read-only)
- Production実行
- Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT TOP (1)
at.transaction_id,
at.transaction_begin_time,
DATEDIFF(SECOND, at.transaction_begin_time, GETDATE()) AS open_seconds,
st.session_id,
st.open_transaction_count,
es.login_name,
es.host_name,
es.program_name,
es.status AS session_status
FROM sys.dm_tran_active_transactions AS at
INNER JOIN sys.dm_tran_session_transactions AS st
ON at.transaction_id = st.transaction_id
LEFT JOIN sys.dm_exec_sessions AS es
ON st.session_id = es.session_id
WHERE st.is_user_transaction = 1
ORDER BY at.transaction_begin_time ASC;When the transaction log is not being released (`log_reuse_wait_desc = ACTIVE_TRANSACTION`), this "oldest transaction" is the very first thing you need. Log after this point cannot be truncated.
- 対象
- SQL Server 2008 and later / Amazon RDS for SQL Server
- 権限
- VIEW SERVER STATE
- 変更作業
- None (read-only)
- Production実行
- Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
r.session_id,
r.status,
r.command,
r.blocking_session_id,
r.wait_type,
r.wait_time,
r.cpu_time,
r.total_elapsed_time,
r.open_transaction_count,
r.percent_complete, -- ROLLBACK など一部の操作で進捗率が入る
SUBSTRING(
t.text,
(r.statement_start_offset / 2) + 1,
((CASE r.statement_end_offset
WHEN -1 THEN DATALENGTH(t.text)
ELSE r.statement_end_offset
END - r.statement_start_offset) / 2) + 1
) AS running_statement
FROM sys.dm_exec_requests AS r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.session_id <> @@SPID
ORDER BY r.total_elapsed_time DESC;Use this to determine whether a session found in the first query "is still executing something, or has finished executing and only has an open transaction left." If `status` is running/suspended, it is still processing; if `sys.dm_exec_requests` has no row for it, processing has finished and only the transaction remains.
- 対象
- SQL Server 2008 and later / Amazon RDS for SQL Server
- 権限
- sysadmin fixed server role or db_owner fixed database role
- 変更作業
- None (read-only)
- Production実行
- Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: sysadmin または db_owner
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
USE [SampleDB];
GO
DBCC OPENTRAN;Returns information about the oldest active transaction in the target database, and any transactions not yet distributed by replication. If there is no open transaction, it returns a message to the effect of "no active open transactions." It carries less detail than the DMVs, but lets you grasp the situation with a single statement.
- 対象
- SQL Server 2008 and later / Amazon RDS for SQL Server
- 権限
- ALTER ANY CONNECTION, or processadmin / sysadmin
- 変更作業
- Yes (forcibly terminates the session and rolls back any uncommitted transaction)
- Production実行
- Not allowed as a rule. Confirm the scope of impact and obtain business sign-off before running
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: ALTER ANY CONNECTION / processadmin / sysadmin
-- 変更作業: あり(セッション強制終了 → 未コミットトランザクションのロールバック)
-- Production 実行: 原則不可。業務影響の確認と承認を得てから実行すること
-- 57 は前掲のクエリで特定した session_id に置き換える
KILL 57;
-- 既にロールバック中のセッションについて進捗率を確認する
KILL 57 WITH STATUSONLY;`KILL` only starts the rollback; the time to completion is proportional to the amount of change the original transaction made. Forcibly terminating a long-running update can make the rollback take even longer. `WITH STATUSONLY` only returns progress for a session already rolling back.
How to Read the Results
| Column | Meaning | What to Check |
|---|---|---|
| transaction_begin_time | Transaction start time | Whether the gap from the current time is implausibly long for the business process |
| open_seconds | Seconds the transaction has been open (computed) | Hundreds of seconds to hours strongly suggests it has been abandoned |
| transaction_type | 1 = read/write / 2 = read-only / 3 = system / 4 = distributed | 1 and 4 block log release; 2 has little impact |
| transaction_state | 2 = active / 3 = ended as read-only / 7 = rolling back | If it stays at 7, it is already rolling back — repeated KILLs won't speed that up |
| open_transaction_count | Number of open transactions on that session | 2 or more means nested transactions remain open |
| session_status | Session status (running / sleeping, etc.) | Sleeping with an open transaction is the typical abandoned pattern |
| program_name / host_name / login_name | Originating application, host, and login | Identifies which application is responsible — useful for deciding who to route the fix to |
| last_statement | The last SQL executed on that connection | Check for the pattern of a BEGIN TRAN with no matching commit |
| blocking_session_id | ID of the blocking session | A nonzero value means you need to trace the blocking chain further |
When to Use This
- The transaction log is not being released, and `log_reuse_wait_desc` stays fixed at ACTIVE_TRANSACTION
- Updates to a specific table are blocked for long periods, causing frequent timeouts
- Restarting the application temporarily resolves it, but it recurs after a while
- Lock-waiting sessions pile up and the connection count approaches its limit
Possible Causes (Most Likely First)
01
The application does not commit or roll back after BEGIN TRAN
If exception handling has a path where neither commit nor rollback is reached, the transaction remains open even after the connection returns to the pool. This shows up as `session_status` being sleeping while a transaction is still open.
02
A transaction was left open from an interactive tool
This happens when someone runs `BEGIN TRAN` in a management tool and walks away without closing the window. You can identify this by `program_name`.
03
A rollback of a large update is in progress
If `transaction_state = 7`, it is already rolling back. There is no way to shorten this state other than waiting — repeated `KILL`s will not speed it up.
04
An unresolved distributed transaction remains open
A distributed transaction (`transaction_type = 4`) depends on the state of the coordinator (MS DTC). Database-side operations alone may not resolve it.
05
Application-side timeout and DB-side wait are out of sync
Even if the client times out and abandons the operation, the server-side transaction does not end automatically — it remains until the connection is closed.
Diagnostic Steps
- 1
List open transactions
Read-onlyRun the first SQL and check entries with the largest `open_seconds` first.
- 2
Identify the oldest transaction
Read-onlyIf log release has stopped, the single oldest transaction is the cause. Narrow it down with the second SQL.
- 3
Determine whether it is still processing or abandoned
Read-onlyCheck whether `sys.dm_exec_requests` has a row for that session. No row means processing has finished and only the transaction remains.
- 4
Trace the blocking chain
Read-onlyFollow `blocking_session_id` to identify the session at the root of the chain. Stopping anything other than the root will not resolve it.
- 5
Identify the originating application
Read-onlyUse `program_name`, `host_name`, and `client_net_address` to determine which application and server the connection is coming from.
- 6
Check whether it recurs at the same time of day
Read-onlyCross-reference against execution history to see whether it coincides with a scheduled batch.
Solutions
Low-risk action that can be done immediately
Have the responsible application commit or roll back
LowEnding the transaction through the application's normal code path is the safest option. Coordinate with the operations team to let that process complete.
Check first whether it is already rolling back
Read-onlyIf `transaction_state = 7`, it is already rolling back. Check progress with `KILL ... WITH STATUSONLY` and wait for completion. An additional `KILL` accomplishes nothing.
Change requiring advance review
Fix the application's exception handling
LowUse a try/finally-equivalent structure so a commit or rollback always runs. This is the most reliably effective fix to prevent recurrence.
Shorten the scope of the transaction
LowRedesign the code so the transaction never spans an external API call or a wait for user input.
Add monitoring for long-running transactions
Read-onlySet up detection and alerting for sessions where `open_seconds` exceeds a threshold, based on the longest legitimate batch duration.
Consider applying SET XACT_ABORT
MediumIf there is a path where a runtime error leaves a transaction half-finished, consider applying `SET XACT_ABORT ON`. This changes the behavior of existing processing, so verify it in a test environment first.
Change involving a restart or service impact
Forcibly terminate the session (KILL)
HighUncommitted changes will be rolled back. The rollback can take as long as, or longer than, the original operation, and the log remains unreleased throughout. This is a last resort that requires business sign-off.
Manually resolve a distributed transaction
Expert Review RequiredAn unresolved distributed transaction requires checking the state on the coordinator side. Forcibly resolving it from the database side alone can break consistency, so this assumes expert review.
!Warnings
- `KILL` rolls back an uncommitted transaction. The log is not released and table locks are not freed until the rollback completes — stopping it does not necessarily mean an immediate fix.
- Repeating `KILL` against a session where `transaction_state = 7` (already rolling back) will not speed up the process. Check progress with `WITH STATUSONLY` and wait.
- In a blocking chain, stopping the tail end without identifying the root session changes nothing. Always trace `blocking_session_id` back to its origin.
- Do not run `KILL` against system transactions (`transaction_type = 3`) or internal sessions.
- `sys.dm_exec_sql_text` returns the text of the entire batch. To see the statement currently executing, you need to extract it using `statement_start_offset` / `statement_end_offset`.
Differences by Version and Environment
If This Doesn't Resolve It
Breakdown of lock waits
Check `sys.dm_tran_locks` to see which resource has which lock mode held against it.
The application's connection pool settings
Check whether the transaction is reset when a connection returns to the pool, and the pool's max size and wait timeout.
Execution history of batch jobs
Check `msdb.dbo.sysjobhistory` for any job running at the same time.
Isolation level settings
Check the application-side configuration for whether a higher-than-default isolation level is being held for a long time.
Basis and Limitations of This Document
Explanation based on official product documentation
A general procedure based on the public specifications of SQL Server's dynamic management views (`sys.dm_tran_active_transactions`, `sys.dm_tran_session_transactions`, `sys.dm_exec_sessions`, `sys.dm_exec_connections`, `sys.dm_exec_requests`), the dynamic management function `sys.dm_exec_sql_text`, and `DBCC OPENTRAN` / `KILL`. It does not include any specific customer's environment or measured values.
FAQ
Can this be run in production?
The four SQL statements used for listing and identification (including `DBCC OPENTRAN`) are read-only and can be run in production. `KILL` is a change operation that rolls back an uncommitted transaction, so it requires confirming the scope of impact and obtaining business sign-off first.
Does this work on AWS RDS?
Yes. Every DMV in this article can be queried on Amazon RDS for SQL Server, and `KILL` can also be run there. Filter on `is_user_transaction = 1` so you do not accidentally target a system session managed by RDS.
What permissions are required?
The read-only SQL requires VIEW SERVER STATE. `DBCC OPENTRAN` requires sysadmin or db_owner on the target database; `KILL` requires ALTER ANY CONNECTION (or processadmin / sysadmin).
Why does it not finish even after I run KILL?
`KILL` is a command that starts a rollback; the time to completion depends on how much data the original transaction changed. `transaction_state = 7` indicates a rollback in progress, and waiting is the only option in that state.
How should I interpret the results?
If `open_seconds` clearly exceeds the longest legitimate processing time for the business, and `sys.dm_exec_requests` has no row for that session, you are looking at a case where "processing has finished but the transaction is still open." That is what needs to be addressed.
Questions This Document Covers
- Detecting abandoned BEGIN TRAN sessions
- I want to find uncommitted transactions in SQL Server
- I want to identify the transaction preventing the log from being released
- I want to find the originating session of a blocking chain
What the Risk Labels Mean
- Read-onlyDoes not change data or settings.
- LowImpact is limited, but permissions and load should be checked.
- MediumMay affect performance, locking, or cost.
- HighMay cause an outage, data loss, or require recovery work.
- Expert Review RequiredRequires a separate review before applying to production.
GIIP's Scope of Support
An abandoned transaction has the property that no one notices it the moment it happens — by the time it surfaces as log exhaustion or blocking, the business process has already stopped. At GIIP, we periodically pull transaction open-duration data across multiple databases, and once a threshold is crossed, an AI agent identifies the responsible session and originating application before notifying the person in charge. High-impact operations like `KILL` are never run automatically — judgment and approval remain a human responsibility.
Author & Technical Review
GIIP Production Operations Team
About 30 years of experience in designing, migrating, and operating large-scale web services, SQL Server, Oracle, AWS, and Azure. Experience includes 12 sets of x12large-class AWS RDS for SQL Server environments, an Oracle environment with roughly 120,000 tables, and migrating roughly 3TB from TiDB to Aurora MySQL. AI agents and human experts currently continue to monitor and operate multiple cloud databases and about 30 web services.
How to Check Transaction Log Usage on RDS for SQL Server
A read-only procedure that checks log usage with DBCC SQLPERF(LOGSPACE) and sys.dm_db_log_space_usage, and isolates the reason it is not being released using log_reuse_wait_desc.
sql-serverCauses and Checks for High CXPACKET Waits in SQL Server
A procedure for evaluating CXPACKET using sys.dm_os_wait_stats and sys.dm_os_waiting_tasks, distinguishing it from CXCONSUMER, and moving toward a review of the degree of parallelism.
sql-serverSQL to Check Statistics Last-Updated Time per Table in SQL Server
A read-only SQL script using sys.stats and STATS_DATE that lists the last-updated time and the number of rows modified since the last update, per table and statistic.
monitoringWhat to Configure When Monitoring Servers and Databases 24/7
A checklist, organized by layer, of what to monitor, how to think about thresholds, the escalation structure, and why synthetic monitoring is necessary when designing 24/7 monitoring.
Related Services
Design monitoring for long-running transactions
If you need to repeat the same checks across multiple environments, we can discuss your entire operations setup.
Design monitoring for long-running transactions