giip
SES Proposal
SQL ServerHighトランザクションロック障害対応ログファイル

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

ProductSQL Server / Amazon RDS for SQL Server / Azure SQL Managed Instance
Verified VersionsSQL Server 2008 and later
EnvironmentOn-premises, EC2, Amazon RDS, Azure
Required PermissionsThe read-only SQL requires VIEW SERVER STATE. `DBCC OPENTRAN` requires sysadmin or db_owner. `KILL` requires ALTER ANY CONNECTION (or processadmin / sysadmin)
Execution ImpactThe read-only SQL makes no changes. `KILL` forcibly terminates a session and rolls back any uncommitted transaction
RestartNot required
Last Verified2026-08-13

Ready-to-Run Commands

List of open transactions (start time, session, most recent SQL)Read-only
対象
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.

Identify only the single oldest transactionRead-only
対象
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.

Currently executing statement and wait state (sys.dm_exec_requests)Read-only
対象
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.

Quick check of the target database's oldest transaction (DBCC OPENTRAN)Read-only
対象
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.

Forcibly terminate a session (last resort — requires approval)High
対象
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

ColumnMeaningWhat to Check
transaction_begin_timeTransaction start timeWhether the gap from the current time is implausibly long for the business process
open_secondsSeconds the transaction has been open (computed)Hundreds of seconds to hours strongly suggests it has been abandoned
transaction_type1 = read/write / 2 = read-only / 3 = system / 4 = distributed1 and 4 block log release; 2 has little impact
transaction_state2 = active / 3 = ended as read-only / 7 = rolling backIf it stays at 7, it is already rolling back — repeated KILLs won't speed that up
open_transaction_countNumber of open transactions on that session2 or more means nested transactions remain open
session_statusSession status (running / sleeping, etc.)Sleeping with an open transaction is the typical abandoned pattern
program_name / host_name / login_nameOriginating application, host, and loginIdentifies which application is responsible — useful for deciding who to route the fix to
last_statementThe last SQL executed on that connectionCheck for the pattern of a BEGIN TRAN with no matching commit
blocking_session_idID of the blocking sessionA 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)

  1. 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.

  2. 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`.

  3. 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.

  4. 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.

  5. 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. 1

    List open transactions

    Read-only

    Run the first SQL and check entries with the largest `open_seconds` first.

  2. 2

    Identify the oldest transaction

    Read-only

    If log release has stopped, the single oldest transaction is the cause. Narrow it down with the second SQL.

  3. 3

    Determine whether it is still processing or abandoned

    Read-only

    Check whether `sys.dm_exec_requests` has a row for that session. No row means processing has finished and only the transaction remains.

  4. 4

    Trace the blocking chain

    Read-only

    Follow `blocking_session_id` to identify the session at the root of the chain. Stopping anything other than the root will not resolve it.

  5. 5

    Identify the originating application

    Read-only

    Use `program_name`, `host_name`, and `client_net_address` to determine which application and server the connection is coming from.

  6. 6

    Check whether it recurs at the same time of day

    Read-only

    Cross-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

    Low

    Ending 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-only

    If `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

    Low

    Use 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

    Low

    Redesign the code so the transaction never spans an external API call or a wait for user input.

  • Add monitoring for long-running transactions

    Read-only

    Set up detection and alerting for sessions where `open_seconds` exceeds a threshold, based on the longest legitimate batch duration.

  • Consider applying SET XACT_ABORT

    Medium

    If 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)

    High

    Uncommitted 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 Required

    An 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

SQL Server 2008 and laterAll the DMVs used in this article (`sys.dm_tran_active_transactions`, `sys.dm_tran_session_transactions`, `sys.dm_exec_sessions`, `sys.dm_exec_connections`, `sys.dm_exec_requests`) are available.
Amazon RDS for SQL ServerThe read-only DMVs and `KILL` are available. However, since RDS-managed system sessions exist, filter on `is_user_transaction = 1` before judging.
Azure SQL DatabaseServer-scoped DMVs have restrictions. Whether you can get equivalent information at the database scope depends on the target service's specifications (verify before relying on this).

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.

Related Knowledge

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

← Back to Knowledge Base