DBA Scripts: Get Active Connections by Database

🔧Part of the DBA-Tools Project, copy/paste SQL Server scripts and health checks.In: Performance & Troubleshooting

The Check Before You Take Anything Offline

Taking a database offline, whether for a decommission, a restore, or a maintenance operation that needs exclusive access, starts with the same question: is anyone actually using it right now? Guessing wrong means an unexpected outage for whoever was still connected.

This script answers that in one pass across every database at once: session count, active requests, open transactions, and blocked sessions, so you can see at a glance which databases are genuinely quiet and which ones aren’t.


Why Active Connections by Database Matters

  • A database can look unused from the application side (no recent deploys, no known active project) while still carrying real, active sessions from a forgotten integration or a scheduled job
  • open_transaction_count catches something a simple session count can’t: a database with an open transaction sitting idle is not safe to touch, even if nothing is actively running against it
  • oldest_conn_min surfaces long-lived connections, useful for spotting connection pool leaks or an application that isn’t cycling its connections as expected
  • Checking every database in one pass, rather than one at a time, is what makes this practical to run routinely rather than only during an incident

When to Run This Script

  • Immediately before taking any database offline, restoring over it, or starting a decommission
  • Investigating unexpected connection counts or a suspected connection leak
  • Routine health checks, to build a baseline sense of which databases are quiet and which are genuinely busy
  • Before a maintenance window that needs exclusive database access, to confirm the window will actually be uncontested

The Script

✓ Verified

  • Tested on: SQL Server 2025 (RTM CU5), Windows lab instance
  • Last verified: 2026-08-13 (saved output from a real run, Get-ActiveConnectionsByDatabase-20260813-184500.csv)
  • Permissions: VIEW SERVER STATE
  • Safety: read-only, impact low

Any thresholds in this script are operational heuristics; claim types are labelled where they appear in the text.

/*
Script Name : Get-ActiveConnectionsByDatabase
Category    : monitoring
Purpose     : Session count, active requests, open transactions, and blocked sessions grouped by database — essential check before taking any database offline or starting a decommission.
Author      : Peter Whyte (https://sqldba.blog/dba-scripts-get-active-connections-by-database/)
Requires    : VIEW SERVER STATE
*/
-- SAFE:ReadOnly
-- IMPACT:Low
SET NOCOUNT ON;

SELECT
    DB_NAME(s.database_id) AS database_name,
    COUNT(*) AS total_sessions,
    SUM(CASE WHEN s.status = 'running' THEN 1 ELSE 0 END) AS active_requests,
    SUM(CASE WHEN s.open_transaction_count > 0 THEN 1 ELSE 0 END) AS open_transactions,
    SUM(CASE WHEN r.blocking_session_id > 0 THEN 1 ELSE 0 END) AS blocked_sessions,
    COUNT(DISTINCT s.login_name) AS distinct_logins,
    MAX(DATEDIFF(MINUTE, s.login_time, GETDATE())) AS oldest_conn_min,
    MIN(s.login_time) AS oldest_login_time
FROM sys.dm_exec_sessions s
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
WHERE s.is_user_process = 1
  AND s.database_id > 0
GROUP BY s.database_id
ORDER BY total_sessions DESC, active_requests DESC;

is_user_process = 1 filters out SQL Server’s own background and system sessions, so the counts reflect real application and user activity only.


How To Run From The Repo

Clone DBA Tools, initialize and run the script:

# Clone dba-tools repo:
git clone https://github.com/peterwhyte-lgtm/dba-tools

# Initialize environment:
cd dba-tools
.\Initialize-Environment.ps1

# Session counts and activity, grouped by database:
.\run.ps1 Get-ActiveConnectionsByDatabase

# To run against a remote sql server:
.\run.ps1 Get-ActiveConnectionsByDatabase -ServerInstance SQLSERVER01

This script lives in the repo at:


Example Output

Six databases with user sessions, and the first row is the one that would stop a maintenance window. DemoDatabase has five sessions, four of them holding open transactions and three of them blocked, which is a database in the middle of doing something, not one waiting quietly to be taken offline.

SSMS results grid from the Get-ActiveConnectionsByDatabase script listing six databases by session count, where DemoDatabase has five sessions with four open transactions and three blocked sessions, and msdb shows a connection over sixteen thousand minutes old

The contrast in the rest of the table is the useful part. DBAMonitor carries four sessions and no transactions at all, a connection pool at rest. And msdb’s oldest connection is over sixteen thousand minutes old, which sounds alarming until you recognise it as SQL Agent itself: long-running tooling connections are normal, and knowing which is which is the difference between planning around a real constraint and postponing for a phantom one.


Understanding the Results

database_name
total_sessions
One row per database that currently has user sessions. A database missing from the results entirely has none, which is the safest possible state to take it offline or restore over.
active_requests
Sessions actually executing right now, as opposed to connected and idle. A high session count with zero active requests is a connection pool at rest, not a busy database.
open_transactions
Sessions holding an open transaction. Act when this is above zero and you are about to take the database offline, restore over it, or detach it. Something is still in flight even if the session looks idle, and this count matters more than the session total. Treat it as a hard stop, not a warning.
blocked_sessions
Sessions currently waiting on another session’s lock. Act when anything is blocked before you add load. Blocking already in progress only gets worse under maintenance, a restore, or a large job starting.
distinct_logins
How many different accounts are connected. One login across many sessions is usually an application pool; many logins usually means people, and people need telling before you take something away.
oldest_conn_min
oldest_login_time
The age of the longest surviving connection to that database. Act when it is unexpectedly high. Either that is legitimate tooling such as a monitoring agent, or an application that is not recycling connections as designed. Both are worth knowing before planning an outage around them.


Best Practices

  • Run this immediately before any operation requiring exclusive database access, don’t rely on assumptions about which databases are “known to be unused”
  • Treat any nonzero open_transactions as a blocker, not just a number to note, confirm what’s holding it open before proceeding
  • Build a routine baseline of normal connection patterns per database, so an unusual spike or an unexpectedly quiet database both stand out
  • Cross-reference a surprising result with Server Inventory scripts if a database shows activity nobody expected

Microsoft’s reference covers sys.dm_exec_sessions and sys.dm_exec_requests in full.


Related Scripts

You may also find these scripts useful:


Frequently Asked Questions

Is a database with zero active sessions definitely safe to take offline?

It’s the strongest signal available from this script, but confirm there isn’t a scheduled job or integration that connects only periodically. A quiet snapshot at the moment you check doesn’t guarantee nothing will connect five minutes later, pair this with knowledge of the database’s actual scheduled workload.

Why does open_transaction_count matter more than active_requests?

active_requests only shows sessions currently executing a statement. A session can hold an open transaction while sitting idle between statements, showing as sleeping rather than running, but still holding locks and blocking cleanup. open_transaction_count catches that case specifically.


Summary

“Is anyone using this database” is a question worth answering with data, not an assumption, before any operation that needs exclusive access. This script answers it across every database in one pass, and the open_transaction_count column catches the specific case a simple connection count would miss: a session sitting idle while still holding a transaction open.

Run it immediately before any decommission, restore, or exclusive-access maintenance window, and treat any nonzero open transaction as a hard stop until you know what’s holding it.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *