Skip to content

ORA-12519 TNS No Appropriate Service Handler - Connection Pool Management

ORA-12519: TNS:No Appropriate Service Handler Found

Section titled “ORA-12519: TNS:No Appropriate Service Handler Found”

Error Text: ORA-12519: TNS:no appropriate service handler found to handle this type of request

This error occurs when the Oracle listener cannot find an available process to handle incoming connection requests. It typically indicates that all available server processes are busy, or connection limits have been reached. This is common in high-traffic environments or when connection pooling is not properly configured.

Client Connection Request
Oracle Listener (Port 1521)
Available Handlers?
├── Dedicated Servers ← Busy/Limit Reached
├── Shared Servers ← Pool Exhausted
└── Dispatchers ← All Occupied
ORA-12519 Error
  • Dedicated Servers - One process per session
  • Shared Servers - Multiple sessions share processes
  • Dispatchers - Route requests to shared servers
  • Connection Pools - Pre-established connections
  • PROCESSES parameter too low
  • SESSIONS parameter insufficient
  • Too many concurrent connections
  • Insufficient dispatchers
  • Shared server pool exhausted
  • Queue overflow
  • Memory exhaustion
  • OS process limits
  • File descriptor limits
  • Connection leaks
  • No connection pooling
  • Poor connection management
-- Current vs maximum sessions
SELECT
'Sessions' as metric,
COUNT(*) as current_value,
(SELECT value FROM v$parameter WHERE name = 'sessions') as max_value,
ROUND(COUNT(*) / (SELECT value FROM v$parameter WHERE name = 'sessions') * 100, 2) as pct_used
FROM v$session
UNION ALL
SELECT
'Processes' as metric,
COUNT(*) as current_value,
(SELECT value FROM v$parameter WHERE name = 'processes') as max_value,
ROUND(COUNT(*) / (SELECT value FROM v$parameter WHERE name = 'processes') * 100, 2) as pct_used
FROM v$process;
-- Session breakdown by status and type
SELECT
status,
server,
COUNT(*) as session_count,
ROUND(COUNT(*) / (SELECT COUNT(*) FROM v$session) * 100, 2) as percentage
FROM v$session
GROUP BY status, server
ORDER BY session_count DESC;
-- Process utilization
SELECT
program,
COUNT(*) as process_count
FROM v$process
WHERE program IS NOT NULL
GROUP BY program
ORDER BY process_count DESC;
-- Check service handlers
SELECT
name as service_name,
max_connections,
current_connections,
available_connections,
blocked_connections
FROM gv$service_metrics
ORDER BY current_connections DESC;
-- Dispatcher configuration and status
SELECT
name,
status,
accept,
idle,
busy,
max_connections,
current_connections
FROM v$dispatcher;
-- Shared server queue status
SELECT
queue,
queued,
wait,
totalq
FROM v$queue
WHERE queue IN ('COMMON', 'DISPATCHER');
-- Sessions by machine and program
SELECT
machine,
program,
COUNT(*) as session_count,
MAX(logon_time) as last_logon
FROM v$session
WHERE username IS NOT NULL
GROUP BY machine, program
ORDER BY session_count DESC;
-- Long-running sessions
SELECT
sid,
serial#,
username,
program,
machine,
status,
ROUND((SYSDATE - logon_time) * 24, 2) as hours_connected,
sql_id
FROM v$session
WHERE username IS NOT NULL
AND (SYSDATE - logon_time) * 24 > 1 -- Connected > 1 hour
ORDER BY hours_connected DESC;
-- Sessions consuming most resources
SELECT
s.sid,
s.serial#,
s.username,
s.program,
p.pga_used_mem/1024/1024 as pga_mb,
s.status,
s.sql_id
FROM v$session s, v$process p
WHERE s.paddr = p.addr
AND s.username IS NOT NULL
AND p.pga_used_mem > 50*1024*1024 -- > 50MB
ORDER BY p.pga_used_mem DESC;
-- Check current parameters
SHOW PARAMETER processes;
SHOW PARAMETER sessions;
SHOW PARAMETER db_files;
-- Increase process limit (requires restart)
ALTER SYSTEM SET processes = 500 SCOPE=SPFILE;
-- Sessions is calculated as: processes * 1.1 + 5
-- But can be set explicitly
ALTER SYSTEM SET sessions = 600 SCOPE=SPFILE;
-- Restart database
SHUTDOWN IMMEDIATE;
STARTUP;
-- Verify changes
SELECT name, value FROM v$parameter
WHERE name IN ('processes', 'sessions');
-- Find inactive sessions to kill
SELECT
'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;' as kill_cmd,
username,
program,
machine,
status,
ROUND((SYSDATE - last_call_et/86400), 2) as days_inactive
FROM v$session
WHERE status = 'INACTIVE'
AND username IS NOT NULL
AND last_call_et > 3600 -- Inactive > 1 hour
ORDER BY last_call_et DESC;
-- Kill specific sessions (execute generated commands)
ALTER SYSTEM KILL SESSION '123,456' IMMEDIATE;
-- Kill all sessions for a specific user (be careful!)
BEGIN
FOR rec IN (
SELECT sid, serial# FROM v$session
WHERE username = 'PROBLEM_USER' AND status = 'INACTIVE'
) LOOP
EXECUTE IMMEDIATE 'ALTER SYSTEM KILL SESSION ''' ||
rec.sid || ',' || rec.serial# || ''' IMMEDIATE';
END LOOP;
END;
/
-- Enable shared server mode
ALTER SYSTEM SET shared_servers = 10 SCOPE=BOTH;
ALTER SYSTEM SET dispatchers = '(PROTOCOL=TCP)(DISPATCHERS=5)' SCOPE=BOTH;
-- Set maximum shared servers
ALTER SYSTEM SET max_shared_servers = 20 SCOPE=BOTH;
-- Check shared server status
SELECT
'Shared Servers' as component,
servers_started,
servers_terminated,
servers_highwater
FROM v$shared_server_monitor;
-- Monitor dispatcher queues
SELECT
network,
dispatchers,
connections,
max_connections,
avg_wait_time
FROM v$dispatcher_config;
-- Implement connection timeout
ALTER SYSTEM SET sqlnet.expire_time = 30 SCOPE=BOTH;
-- Set idle timeout for sessions
CREATE PROFILE connection_profile LIMIT
IDLE_TIME 30 -- 30 minutes idle timeout
CONNECT_TIME 480 -- 8 hours max connection time
SESSIONS_PER_USER 5; -- Max 5 concurrent sessions per user
-- Apply profile to users
ALTER USER app_user PROFILE connection_profile;
-- Resource manager for connection limits
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN(
plan => 'CONNECTION_LIMIT_PLAN',
comment => 'Limit connections per consumer group'
);
DBMS_RESOURCE_MANAGER.CREATE_CONSUMER_GROUP(
consumer_group => 'APP_USERS',
comment => 'Application users group'
);
DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(
plan => 'CONNECTION_LIMIT_PLAN',
group_or_subplan => 'APP_USERS',
max_active_sess_target_mth => 'ACTIVE_SESS_POOL_P1',
active_sess_pool_p1 => 50 -- Max 50 active sessions
);
END;
/
// Java connection pooling example
// Use connection pools instead of direct connections
// BAD: Direct connections
Connection conn = DriverManager.getConnection(url, user, pass);
// ... use connection
conn.close(); // Often forgotten!
// GOOD: Connection pooling
// HikariCP configuration
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:oracle:thin:@server:1521:orcl");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(20); // Max connections
config.setMinimumIdle(5); // Min idle connections
config.setConnectionTimeout(30000); // 30 second timeout
config.setIdleTimeout(600000); // 10 minute idle timeout
config.setMaxLifetime(1800000); // 30 minute max lifetime
config.setLeakDetectionThreshold(60000); // Detect leaks after 1 minute
HikariDataSource dataSource = new HikariDataSource(config);
// Use try-with-resources to ensure connections are closed
try (Connection conn = dataSource.getConnection()) {
// Use connection
PreparedStatement ps = conn.prepareStatement("SELECT ...");
ResultSet rs = ps.executeQuery();
// Process results
} // Connection automatically returned to pool
-- Create monitoring table
CREATE TABLE dba_connection_alerts (
alert_time TIMESTAMP DEFAULT SYSTIMESTAMP,
alert_type VARCHAR2(50),
current_sessions NUMBER,
max_sessions NUMBER,
utilization_pct NUMBER,
details VARCHAR2(500)
);
-- Monitoring procedure
CREATE OR REPLACE PROCEDURE monitor_connections AS
v_current_sessions NUMBER;
v_max_sessions NUMBER;
v_utilization_pct NUMBER;
v_current_processes NUMBER;
v_max_processes NUMBER;
BEGIN
-- Get session utilization
SELECT COUNT(*) INTO v_current_sessions FROM v$session;
SELECT value INTO v_max_sessions FROM v$parameter WHERE name = 'sessions';
v_utilization_pct := (v_current_sessions / v_max_sessions) * 100;
-- Alert if utilization > 80%
IF v_utilization_pct > 80 THEN
INSERT INTO dba_connection_alerts (
alert_type, current_sessions, max_sessions, utilization_pct, details
) VALUES (
'HIGH_SESSION_UTILIZATION', v_current_sessions, v_max_sessions,
v_utilization_pct, 'Session utilization exceeded 80%'
);
END IF;
-- Check process utilization
SELECT COUNT(*) INTO v_current_processes FROM v$process;
SELECT value INTO v_max_processes FROM v$parameter WHERE name = 'processes';
IF (v_current_processes / v_max_processes) * 100 > 85 THEN
INSERT INTO dba_connection_alerts (
alert_type, current_sessions, max_sessions, utilization_pct, details
) VALUES (
'HIGH_PROCESS_UTILIZATION', v_current_processes, v_max_processes,
(v_current_processes / v_max_processes) * 100, 'Process utilization exceeded 85%'
);
END IF;
COMMIT;
END;
/
-- Schedule monitoring
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'MONITOR_CONNECTIONS',
job_type => 'STORED_PROCEDURE',
job_action => 'monitor_connections',
repeat_interval => 'FREQ=MINUTELY; INTERVAL=5',
enabled => TRUE
);
END;
/
Terminal window
# Edit listener.ora to add service limits
vi $ORACLE_HOME/network/admin/listener.ora
# Add connection limits
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = server)(PORT = 1521))
)
)
# Service-specific limits
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = orcl.domain.com)
(ORACLE_HOME = /u01/app/oracle/product/19.0.0/dbhome_1)
(SID_NAME = orcl)
(ENVS = "MAX_CONNECTIONS=100")
)
)
# Reload listener configuration
lsnrctl reload
Terminal window
# Add to listener.ora
RATE_LIMIT_LISTENER = ON
CONNECTION_RATE_LISTENER = 50 # Max 50 connections per second
# Monitor listener statistics
lsnrctl services
lsnrctl status
# Check listener log for connection patterns
tail -f $ORACLE_BASE/diag/tnslsnr/*/listener/trace/listener.log
Terminal window
# Check current limits
ulimit -a
# Increase process limits for oracle user
# Edit /etc/security/limits.conf
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
# Kernel parameters for better connection handling
# Edit /etc/sysctl.conf
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1800
# Apply changes
sysctl -p
-- Optimize memory for more processes
ALTER SYSTEM SET sga_target = 8G SCOPE=SPFILE;
ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=SPFILE;
-- Or use automatic memory management
ALTER SYSTEM SET memory_target = 10G SCOPE=SPFILE;
ALTER SYSTEM SET memory_max_target = 12G SCOPE=SPFILE;
-- Tune shared pool for more sessions
ALTER SYSTEM SET shared_pool_size = 1G SCOPE=SPFILE;
ALTER SYSTEM SET large_pool_size = 500M SCOPE=SPFILE;
-- Create connection pool analysis view
CREATE OR REPLACE VIEW v_connection_analysis AS
SELECT
machine,
program,
COUNT(*) as connection_count,
COUNT(CASE WHEN status = 'ACTIVE' THEN 1 END) as active_connections,
COUNT(CASE WHEN status = 'INACTIVE' THEN 1 END) as inactive_connections,
AVG(CASE WHEN status = 'INACTIVE' THEN last_call_et ELSE NULL END) as avg_inactive_time,
MAX(last_call_et) as max_inactive_time
FROM v$session
WHERE username IS NOT NULL
GROUP BY machine, program
ORDER BY connection_count DESC;
-- Daily connection pattern analysis
SELECT
TO_CHAR(sample_time, 'HH24') as hour,
AVG(current_utilization) as avg_utilization,
MAX(current_utilization) as max_utilization
FROM (
SELECT
sample_time,
current_utilization
FROM dba_hist_sysmetric_history
WHERE metric_name = 'Current OS Load'
AND sample_time > SYSDATE - 7
)
GROUP BY TO_CHAR(sample_time, 'HH24')
ORDER BY hour;
-- Auto-kill procedure for emergency situations
CREATE OR REPLACE PROCEDURE emergency_connection_cleanup AS
v_session_count NUMBER;
v_max_sessions NUMBER;
v_utilization_pct NUMBER;
BEGIN
-- Get current utilization
SELECT COUNT(*) INTO v_session_count FROM v$session;
SELECT value INTO v_max_sessions FROM v$parameter WHERE name = 'sessions';
v_utilization_pct := (v_session_count / v_max_sessions) * 100;
-- If utilization > 90%, kill oldest inactive sessions
IF v_utilization_pct > 90 THEN
FOR rec IN (
SELECT sid, serial#
FROM v$session
WHERE status = 'INACTIVE'
AND username IS NOT NULL
AND last_call_et > 1800 -- Inactive > 30 minutes
ORDER BY last_call_et DESC
FETCH FIRST 10 ROWS ONLY
) LOOP
EXECUTE IMMEDIATE 'ALTER SYSTEM KILL SESSION ''' ||
rec.sid || ',' || rec.serial# || ''' IMMEDIATE';
END LOOP;
-- Log the action
INSERT INTO dba_connection_alerts (
alert_type, details
) VALUES (
'EMERGENCY_CLEANUP', 'Killed inactive sessions due to high utilization'
);
COMMIT;
END IF;
END;
/
  1. ✓ Check current session/process utilization
  2. ✓ Identify and kill inactive sessions
  3. ✓ Increase process/session limits if needed
  4. ✓ Configure shared servers for better scaling
  5. ✓ Check application connection pooling
  6. ✓ Monitor system resources
  7. ✓ Implement connection timeouts
  8. ✓ Set up automated monitoring
-- Critical parameters for connection management
SELECT name, value FROM v$parameter
WHERE name IN (
'processes',
'sessions',
'shared_servers',
'dispatchers',
'max_shared_servers'
);
-- Session utilization
SELECT
ROUND(COUNT(*) / (SELECT value FROM v$parameter WHERE name = 'sessions') * 100, 2) as session_pct
FROM v$session;
-- Process utilization
SELECT
ROUND(COUNT(*) / (SELECT value FROM v$parameter WHERE name = 'processes') * 100, 2) as process_pct
FROM v$process;
-- Top connection consumers
SELECT machine, program, COUNT(*) as connections
FROM v$session
WHERE username IS NOT NULL
GROUP BY machine, program
ORDER BY connections DESC
FETCH FIRST 10 ROWS ONLY;