ORA-12516, ORA-17800 et Saturation de Process Oracle : Comprendre, Diagnostiquer et Corriger

La gestion des processus Oracle est un sujet qui revient fréquemment en production. Beaucoup d’administrateurs et développeurs rencontrent des erreurs comme :

  • ORA-12516: TNS:listener could not find available handler with matching protocol stack
  • ORA-17800: Got minus one from a read call

Ces erreurs surviennent généralement lorsque la base n’a plus de processus disponibles pour accepter de nouvelles connexions.


🔎 C’est quoi un « process » Oracle ?

Un process est tout simplement un morceau de programme en mémoire qui exécute une tâche.

Dans Oracle, il y a :

  • des processus de fond (DBWR, LGWR, CKPT…) qui assurent le bon fonctionnement interne,
  • des processus serveurs qui gèrent vos connexions (1 connexion = 1 process en mode dedicated),
  • des processus partagés (shared servers, dispatchers),
  • des esclaves parallèles (PX slaves pour les requêtes en parallèle).

Le paramètre PROCESSES définit le nombre maximum de process que l’instance Oracle peut lancer. S’il est atteint → plus de nouvelles connexions possibles.


🚨 Symptômes courants

  • Applications qui plantent avec ORA-12516.
  • Messages réseau comme ORA-17800 (connexion brutalement fermée).
  • Saturation du CPU par de nombreux process Oracle.
  • Alert log montrant des refus de connexion.

🛠 Se connecter directement au serveur Oracle

Lorsque vous êtes connecté sur le serveur qui héberge Oracle, vous pouvez contourner le listener et vous connecter directement à l’instance. Cela est très utile en cas de saturation.

Connexion en OS Authentication (compte oracle sur le serveur)

# Se connecter en tant qu'utilisateur oracle sur l'OS
sqlplus / as sysdba

Connexion classique avec mot de passe

sqlplus sys@ORCL as sysdba
# ou
sqlplus sys/password@ORCL as sysdba

Ici ORCL peut être remplacé par l’SID ou un SERVICE_NAME valide (ex: cdbprod).

En cas de doute :

export ORACLE_SID=CDBPROD
sqlplus / as sysdba

🛠 Diagnostic pas à pas

1. Vérifier l’utilisation des limites

SELECT resource_name, current_utilization, max_utilization, limit_value
FROM   v$resource_limit
WHERE  resource_name IN ('processes','sessions','transactions');

2. Voir combien de process sont actifs

SELECT COUNT(*) AS current_processes FROM v$process;

3. Identifier l’appli/service qui consomme

SELECT s.service_name,
       COALESCE(NULLIF(s.module,''), s.program) AS module,
       s.machine,
       COUNT(*) AS sessions
FROM   gv$session s
WHERE  s.type='USER'
GROUP  BY s.service_name, COALESCE(NULLIF(s.module,''), s.program), s.machine
ORDER  BY sessions DESC
FETCH FIRST 20 ROWS ONLY;

4. Détecter les sessions inactives (potentielles « fuites » de connexions)

SELECT s.service_name, s.program, s.machine,
       COUNT(*) AS idle_cnt, MAX(s.last_call_et) AS max_idle_sec
FROM   gv$session s
WHERE  s.type='USER'
  AND  s.status='INACTIVE'
  AND  s.last_call_et > 30*60
GROUP  BY s.service_name, s.program, s.machine
ORDER  BY idle_cnt DESC;

🗑 Nettoyer les sessions inutiles

Voici un script tout-en-un qui tue automatiquement les sessions inactives depuis plus de 30 minutes, sans transaction en cours, et hors comptes SYS/SYSTEM :

SET SERVEROUTPUT ON SIZE UNLIMITED
DECLARE
  v_killed NUMBER := 0;
BEGIN
  FOR r IN (
    SELECT s.inst_id, s.sid, s.serial#
    FROM   gv$session s
    LEFT JOIN gv$transaction t
           ON t.addr = s.taddr AND t.inst_id = s.inst_id
    WHERE  s.type='USER'
      AND  s.username NOT IN ('SYS','SYSTEM')
      AND  s.status='INACTIVE'
      AND  s.last_call_et > 30*60
      AND  t.addr IS NULL
      AND  s.blocking_session IS NULL
  ) LOOP
    BEGIN
      EXECUTE IMMEDIATE
        'ALTER SYSTEM KILL SESSION '''||r.sid||','||r.serial#||',@'||r.inst_id||''' IMMEDIATE';
      v_killed := v_killed + 1;
    EXCEPTION WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE('FAILED: '||SQLERRM);
    END;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('Killed '||v_killed||' session(s).');
END;
/

⚠ À utiliser avec précaution. Filtrez si possible par SERVICE_NAME, MODULE ou MACHINE pour ne viser que l’application fautive.


🔧 Solutions durables

  1. Augmenter la capacité (redémarrage nécessaire) :
ALTER SYSTEM SET processes = 1500 SCOPE=SPFILE;
ALTER SYSTEM SET sessions  = 2250 SCOPE=SPFILE; -- ~1.5x processes

Puis :

SHUTDOWN IMMEDIATE;
STARTUP;
  1. Configurer le pool de connexions (UCP, Hikari, etc.) :
    • Max pool size raisonnable
    • Idle timeout
    • Validation query (SELECT 1 FROM DUAL)
  2. Paramétrer SQLNET.EXPIRE_TIME pour nettoyer les connexions zombies.
  3. Limiter par profil :
ALTER PROFILE app_profile LIMIT IDLE_TIME 30; -- en minutes
  1. Resource Manager : fixer un plafond de sessions par service ou par utilisateur.

🔐 Connexions locales depuis le serveur (sans et avec listener)

1) Connexion locale sans listener (bequeath) — administration rapide

À exécuter en SSH sur l’hôte de la base ; l’utilisateur OS doit appartenir au groupe OSDBA (dba).

# Définir l'environnement Oracle (adapter ORACLE_HOME/ORACLE_SID)
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=CDBPROD

# Connexion SYS locale (OS authentication)
sqlplus / as sysdba

# (Optionnel) Basculer vers une PDB
SQL> SHOW con_name;
SQL> ALTER SESSION SET CONTAINER=pdbsid;   -- remplacer par votre PDB
SQL> SHOW con_name;

Avantages : pas de dépendance au listener, idéal en incident ou maintenance.


2) Connexion locale via listener TCP (utilise le service)

# Vérifier le listener et les services
lsnrctl status

# Test de résolution / reachability
tnsping //oracle.test.local:1526/pdbsid

# Connexions SQL*Plus
sqlplus user/pass@//oracle.test.local:1526/pdbsid
sqlplus sys@//oracle.test.local:1526/pdbsid as sysdba

TNSNAMES (facultatif, plus lisible)

PDBSID =
  (DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCP)(HOST=oracle.test.local)(PORT=1526))
    (CONNECT_DATA=(SERVICE_NAME=pdbsid)(SERVER=DEDICATED))
  )
sqlplus user/pass@PDBSID
sqlplus sys@PDBSID as sysdba

3) Outils alternatifs

# SQLcl (Oracle) : similaire à SQL*Plus avec améliorations
sql / as sysdba
sql sys@//oracle.test.local:1526/pdbsid as sysdba

4) Conseils & dépannage

  • PDB non ouverte : -- en CDB$ROOT ALTER PLUGGABLE DATABASE ALL OPEN; ALTER PLUGGABLE DATABASE ALL SAVE STATE;
  • Service manquant : SHOW PARAMETER service_names; ALTER SYSTEM REGISTER; -- forcer l'enregistrement auprès du listener lsnrctl services
  • Erreur ORA-12516 : vérifier la capacité processes/sessions et la saturation des handlers (lsnrctl services).
  • Erreur ORA-17800 : vérifier timeouts réseau, keepalive (SQLNET.EXPIRE_TIME=10), et versions de driver côté client.

✅ Conclusion

La saturation de PROCESSES est l’une des causes les plus fréquentes des erreurs ORA-12516 et ORA-17800. Elle est souvent liée à des applications qui ouvrent trop de connexions sans les réutiliser.

En résumé :

  • Court terme : tuer les sessions inactives.
  • Moyen terme : augmenter PROCESSES/SESSIONS.
  • Long terme : corriger le pool applicatif et mettre en place une supervision proactive.

En adoptant ces bonnes pratiques, vous éviterez les interruptions de service et améliorerez la stabilité de vos bases Oracle.


Assistant IA