ORA-00031: Session Marked for Kill - Force Terminate Zombie Sessions
ORA-00031: Session Marked for Kill
Section titled “ORA-00031: Session Marked for Kill”Error Overview
Section titled “Error Overview”Error Text: ORA-00031: session marked for kill
The ORA-00031 error occurs when a DBA issues ALTER SYSTEM KILL SESSION against a session, but the session cannot be terminated immediately. Oracle marks the session for kill and returns this error to indicate the kill request has been acknowledged — but the session is still alive. The session will be cleaned up by PMON (Process Monitor) the next time it attempts a database call, or by Oracle’s internal cleanup mechanisms.
This is one of the most frustrating situations for DBAs: a runaway query, a blocking session, or a zombie connection refuses to die even after an explicit kill command. Understanding why sessions resist termination and what options are available is essential for any production DBA.
Common Causes
Section titled “Common Causes”1. Session Is Waiting on a Slow OS Operation
Section titled “1. Session Is Waiting on a Slow OS Operation”- The session is performing a large I/O operation (e.g., a full table scan writing to a sort area)
- Network I/O in progress — the session is waiting for a response from a database link or remote service
- The OS is waiting on a disk write that cannot be interrupted mid-operation
2. Session Is in the Middle of a Transaction Rollback
Section titled “2. Session Is in the Middle of a Transaction Rollback”- The session had a large, long-running transaction when the kill was issued
- Oracle must roll back all uncommitted changes before the process can be freed
- Rollback time is proportional to the transaction size — very large transactions can take as long to roll back as they did to execute
3. Distributed Transaction Involvement
Section titled “3. Distributed Transaction Involvement”- The session is a participant in a distributed transaction across a database link
- Oracle must coordinate with the remote database before terminating the local session
- Two-phase commit (2PC) in progress prevents immediate cleanup
4. RAC (Real Application Clusters) Considerations
Section titled “4. RAC (Real Application Clusters) Considerations”- The session physically exists on a different RAC node than where the kill was issued
- Cross-instance kill requires inter-node communication and takes longer
- The
@instance_numberqualifier was not used and Oracle is killing the wrong instance
5. Operating System Process Not Responding
Section titled “5. Operating System Process Not Responding”- The server process (shadow process) is stuck in an uninterruptible OS wait
- The OS process is in a kernel wait state (e.g.,
Dstate on Linux) and cannot receive signals - A bug or hardware issue is causing the process to be unkillable through normal means
6. PMON Backlog
Section titled “6. PMON Backlog”- PMON is overloaded with cleanup tasks from many recently killed or disconnected sessions
- The marked-for-kill session is queued behind other cleanup work
- PMON itself is experiencing performance degradation
Diagnostic Queries
Section titled “Diagnostic Queries”Identify the Marked Session
Section titled “Identify the Marked Session”-- Find sessions marked for killSELECT sid, serial#, username, status, last_call_et, blocking_session, event, wait_class, seconds_in_wait, program, machine, osuser, process AS client_pid, sql_idFROM v$sessionWHERE status = 'KILLED'ORDER BY last_call_et DESC;
-- Find the corresponding server process OS PIDSELECT s.sid, s.serial#, s.username, s.status, p.spid AS server_os_pid, p.pid AS oracle_pid, s.last_call_et, s.program, s.machineFROM v$session sJOIN v$process p ON s.paddr = p.addrWHERE s.status = 'KILLED'ORDER BY s.last_call_et DESC;Check What the Session Was Doing
Section titled “Check What the Session Was Doing”-- Identify the SQL the killed session was runningSELECT s.sid, s.serial#, s.username, s.status, s.sql_id, q.sql_text, q.elapsed_time / 1000000 AS elapsed_seconds, q.executionsFROM v$session sLEFT JOIN v$sql q ON s.sql_id = q.sql_idWHERE s.status = 'KILLED';
-- Check for active rollback (undo generation)SELECT s.sid, s.serial#, s.username, t.used_ublk AS undo_blocks_used, t.used_urec AS undo_records_used, t.start_time AS transaction_start, s.last_call_et AS seconds_since_last_callFROM v$session sJOIN v$transaction t ON s.taddr = t.addrWHERE s.status = 'KILLED'ORDER BY t.used_ublk DESC;Check for Blocking Locks Held by the Killed Session
Section titled “Check for Blocking Locks Held by the Killed Session”-- Check if the killed session is still holding locksSELECT l.sid, l.type, l.lmode, l.request, l.id1, l.id2, o.owner, o.object_name, o.object_typeFROM v$lock lLEFT JOIN dba_objects o ON l.id1 = o.object_idWHERE l.sid IN ( SELECT sid FROM v$session WHERE status = 'KILLED')ORDER BY l.sid;
-- Check blocking chains involving killed sessionsSELECT blocker.sid AS blocking_sid, blocker.serial# AS blocking_serial, blocker.status AS blocking_status, blocker.username AS blocking_user, waiter.sid AS waiting_sid, waiter.username AS waiting_user, waiter.event AS waiting_onFROM v$session blockerJOIN v$session waiter ON waiter.blocking_session = blocker.sidWHERE blocker.status = 'KILLED'ORDER BY blocker.sid;Estimate Rollback Completion Time
Section titled “Estimate Rollback Completion Time”-- Estimate how long rollback will takeSELECT s.sid, s.serial#, t.used_ublk AS undo_blocks_remaining, t.used_urec AS undo_records_remaining, ROUND(t.used_ublk * 8192 / 1024 / 1024, 2) AS undo_mb_remaining, TO_CHAR(t.start_scn) AS start_scn, (SYSDATE - TO_DATE(t.start_time, 'MM/DD/YY HH24:MI:SS')) * 24 * 60 AS minutes_runningFROM v$session sJOIN v$transaction t ON s.taddr = t.addrWHERE s.status = 'KILLED';Check PMON Activity
Section titled “Check PMON Activity”-- Check PMON process statusSELECT p.pid, p.spid AS os_pid, p.program, p.background, s.last_call_etFROM v$process pLEFT JOIN v$session s ON p.addr = s.paddrWHERE p.background = 1 AND p.program LIKE '%PMON%';
-- Check for recent session cleanup events in the alert logSELECT originating_timestamp, message_textFROM v$diag_alert_extWHERE originating_timestamp > SYSDATE - 1/24 AND (message_text LIKE '%PMON%' OR message_text LIKE '%dead%' OR message_text LIKE '%cleanup%')ORDER BY originating_timestamp DESC;Step-by-Step Resolution
Section titled “Step-by-Step Resolution”1. Wait and Monitor (First Step — Always)
Section titled “1. Wait and Monitor (First Step — Always)”Before taking drastic action, determine whether the session is actively rolling back:
-- Poll the session every 60 seconds to track rollback progress-- Run this multiple times and compare undo_blocks_remainingSELECT s.sid, s.serial#, s.status, t.used_ublk AS undo_blocks_remaining, t.used_urec AS undo_records_remainingFROM v$session sLEFT JOIN v$transaction t ON s.taddr = t.addrWHERE s.status = 'KILLED';If undo_blocks_remaining is decreasing between polls, the session is rolling back normally. Wait for it to complete — interrupting rollback can lead to data corruption.
2. Re-Issue the Kill with IMMEDIATE Clause
Section titled “2. Re-Issue the Kill with IMMEDIATE Clause”If the original kill was issued without IMMEDIATE, try again with the flag:
-- Re-issue kill with IMMEDIATE to force faster cleanupALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
-- Example:ALTER SYSTEM KILL SESSION '145,23456' IMMEDIATE;The IMMEDIATE clause instructs Oracle to release resources and disconnect the session without waiting for the session to acknowledge the kill request. This is generally safe for sessions not in the middle of a transaction.
3. Kill at the OS Level
Section titled “3. Kill at the OS Level”If Oracle cannot terminate the session through normal means, kill the underlying OS server process:
-- Step 1: Get the OS process ID of the server processSELECT s.sid, s.serial#, s.username, p.spid AS server_os_pidFROM v$session sJOIN v$process p ON s.paddr = p.addrWHERE s.sid = &target_sid AND s.serial# = &target_serial;# Step 2: On Linux/Unix, kill the process with SIGTERM firstkill -15 <spid>
# If SIGTERM does not work after 30 seconds, use SIGKILLkill -9 <spid>
# On Windows, use taskkilltaskkill /F /PID <spid>After an OS-level kill, PMON will detect the dead process and perform cleanup. The session entry will disappear from v$session once PMON finishes.
4. RAC-Specific Kill
Section titled “4. RAC-Specific Kill”In a RAC environment, the session may exist on a different instance:
-- Identify which instance the session exists onSELECT inst_id, sid, serial#, username, status, machineFROM gv$sessionWHERE status IN ('ACTIVE', 'KILLED', 'INACTIVE') AND username IS NOT NULLORDER BY inst_id, sid;
-- Kill a session on a specific instanceALTER SYSTEM KILL SESSION 'sid,serial#,@instance_number' IMMEDIATE;
-- Example: Kill session on instance 2ALTER SYSTEM KILL SESSION '87,14433,@2' IMMEDIATE;5. Disconnect Rather Than Kill (Non-SYSDBA Sessions)
Section titled “5. Disconnect Rather Than Kill (Non-SYSDBA Sessions)”As an alternative to killing, use DISCONNECT SESSION to gracefully disconnect without waiting for a kill acknowledgment:
-- Disconnect immediately (similar to OS-level disconnect)ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' IMMEDIATE;
-- Post-transaction disconnect (waits for current transaction to complete)ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' POST_TRANSACTION;DISCONNECT SESSION IMMEDIATE terminates the server process directly without waiting for PMON cleanup, and is often faster than KILL SESSION with IMMEDIATE.
6. Verify Cleanup Completed
Section titled “6. Verify Cleanup Completed”After the kill or disconnect:
-- Confirm the session is gone from v$sessionSELECT sid, serial#, username, statusFROM v$sessionWHERE sid = &target_sid;
-- Confirm locks are releasedSELECT sid, type, lmode, id1, id2FROM v$lockWHERE sid = &target_sid;
-- Check for orphaned transactionsSELECT xidusn, xidslot, xidsqn, status, start_time, used_ublkFROM v$transactionWHERE ses_addr NOT IN (SELECT saddr FROM v$session);Prevention Strategies
Section titled “Prevention Strategies”1. Set Connection Timeouts to Avoid Zombie Sessions
Section titled “1. Set Connection Timeouts to Avoid Zombie Sessions”-- Create a profile with idle timeoutCREATE PROFILE app_user_profile LIMIT IDLE_TIME 30 -- 30 minutes idle CONNECT_TIME 480 -- 8 hours max connection time SESSIONS_PER_USER 5;
-- Assign the profile to application usersALTER USER app_user PROFILE app_user_profile;
-- Verify profile assignmentsSELECT username, profileFROM dba_usersWHERE profile != 'DEFAULT'ORDER BY username;2. Configure Dead Connection Detection
Section titled “2. Configure Dead Connection Detection”-- Set SQLNET.EXPIRE_TIME in sqlnet.ora to detect dead connections-- Add to $ORACLE_HOME/network/admin/sqlnet.ora:-- SQLNET.EXPIRE_TIME = 10 (minutes)
-- Verify via parameterSELECT name, valueFROM v$parameterWHERE name LIKE '%expire%' OR name LIKE '%dead%';3. Monitor for Long-Running Sessions Proactively
Section titled “3. Monitor for Long-Running Sessions Proactively”-- Create a scheduler job to alert on sessions running > 2 hoursBEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'ALERT_LONG_RUNNING_SESSIONS', job_type => 'PLSQL_BLOCK', job_action => q'[ DECLARE v_count NUMBER; BEGIN SELECT COUNT(*) INTO v_count FROM v$session WHERE status = ''ACTIVE'' AND last_call_et > 7200 AND username IS NOT NULL;
IF v_count > 0 THEN -- Insert into an alerts table or send DBMS_ALERT INSERT INTO dba_monitoring_alerts (alert_time, alert_type, detail) VALUES (SYSDATE, ''LONG_SESSION'', v_count || '' sessions running > 2 hours''); COMMIT; END IF; END; ]', repeat_interval => 'FREQ=MINUTELY;INTERVAL=30', enabled => TRUE );END;/4. Best Practices for Session Management
Section titled “4. Best Practices for Session Management”- Always try
ALTER SYSTEM KILL SESSION ... IMMEDIATEbefore resorting to OS-level kills - In RAC environments, always specify the
@instance_numberqualifier to ensure the correct instance is targeted - Never kill a session that is actively rolling back a large transaction — wait for rollback to complete
- Use connection pools with proper timeout configurations to reduce the occurrence of zombie sessions
- Document any OS-level process kills in change management records for audit purposes
Diagnostic Scripts
Section titled “Diagnostic Scripts”These Oracle Day by Day scripts can help manage and diagnose session issues:
- gvsess.sql — Comprehensive session analysis across all instances
- health.sql — Database health check including session and lock analysis
Related Errors
Section titled “Related Errors”- ORA-00028 - Your session has been killed (received by the killed session)
- ORA-00054 - Resource busy and acquire with NOWAIT specified
- ORA-00060 - Deadlock detected while waiting for resource
- ORA-01013 - User requested cancel of current operation
Emergency Response
Section titled “Emergency Response”Quick Fixes
Section titled “Quick Fixes”-
Re-issue kill with IMMEDIATE
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE; -
Use DISCONNECT SESSION as alternative
ALTER SYSTEM DISCONNECT SESSION 'sid,serial#' IMMEDIATE; -
OS-level process kill as last resort
-- Get OS PID firstSELECT p.spid FROM v$process p JOIN v$session s ON p.addr = s.paddrWHERE s.sid = &sid AND s.serial# = &serial;-- Then: kill -9 <spid> from OS prompt
Post-Resolution Cleanup
Section titled “Post-Resolution Cleanup”-- Confirm session is fully removedSELECT sid, serial#, username, statusFROM v$sessionWHERE status = 'KILLED';
-- Check for orphaned locksSELECT sid, type, lmode, id1, id2FROM v$lock lWHERE sid NOT IN (SELECT sid FROM v$session);
-- Check for orphaned transactions that need cleanupSELECT t.xidusn, t.used_ublk, t.statusFROM v$transaction tWHERE t.ses_addr NOT IN (SELECT saddr FROM v$session);
-- Review alert log for PMON cleanup messagesSELECT originating_timestamp, message_textFROM v$diag_alert_extWHERE originating_timestamp > SYSDATE - 1/24 AND message_text LIKE '%dead%process%'ORDER BY originating_timestamp DESC;