The search order for TNSNAMES.ORA

When reading the headline, you might think the answer is more or less trivial. Or at least it is stated in the docs. But in fact, it isn’t. Let’s have a quick glance at the docs. The “19c Net Services Administrator’s Guide” states the following:

1. The directory specified by the TNS_ADMIN environment variable.
2. If the TNS_ADMIN environment variable is not set or the file is not found in the TNS_ADMIN directory, then Oracle Net checks for the file in the ORACLE_HOME/network/admin directory. For a read-only Oracle home, Oracle Net checks the ORACLE_BASE_HOME/network/admin directory.

So let’s build a testcase to verify that. I created a CDB that hosts a PDB for each type directory, that may hold a tnsnames.ora file. As far as I know, it can reside in the current directory. in a directory pointed to by TNS_ADMIN and in ORACLE_HOME/network/admin. The TNS_ADMIN can be defined as a environment variable or, on Windows, inside the Registry.

SQL> select name from v$database;

NAME
---------
MPMCDB1

SQL> show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 PDBA                           READ WRITE NO
         4 TNSLOCAL                       READ WRITE NO
         5 TNSREGISTRY                    READ WRITE NO
         6 TNSADMIN                       READ WRITE NO
         7 TNSORAHOME                     READ WRITE NO

For the test, I will create a tnsnames.ora in each of the mentioned locations with one alias in it. The only difference will be the service, the alias refers to.

Let’s check these files and settings first.

C:\Users\marco.mischke>type tnsnames.ora
TNSTEST=
 (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = odax5ha0.support.robotron.de)(PORT = 1521))
   (CONNECT_DATA = (SERVICE_NAME = tnslocal.support.robotron.de))
 )


C:\Users\marco.mischke>reg query HKLM\SOFTWARE\Oracle\KEY_OraClient19Home1 /v TNS_ADMIN

HKEY_LOCAL_MACHINE\SOFTWARE\Oracle\KEY_OraClient19Home1
    TNS_ADMIN    REG_SZ    C:\TEMP
    
C:\Users\marco.mischke>type c:\Temp\tnsnames.ora
TNSTEST=
 (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = odax5ha0.support.robotron.de)(PORT = 1521))
   (CONNECT_DATA = (SERVICE_NAME = tnsregistry.support.robotron.de))
 )

C:\Users\marco.mischke>set TNS_ADMIN=c:\Users\marco.mischke\TNSADMIN

C:\Users\marco.mischke>type c:\Users\marco.mischke\TNSADMIN\tnsnames.ora
TNSTEST=
 (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = odax5ha0.support.robotron.de)(PORT = 1521))
   (CONNECT_DATA = (SERVICE_NAME = tnsadmin.support.robotron.de))
 )

C:\Users\marco.mischke>set TNS
TNS_ADMIN=c:\Users\marco.mischke\TNSADMIN

C:\Users\marco.mischke>type C:\oracle\client19\network\admin\tnsnames.ora
TNSTEST=
 (DESCRIPTION =
   (ADDRESS = (PROTOCOL = TCP)(HOST = odax5ha0.support.robotron.de)(PORT = 1521))
   (CONNECT_DATA = (SERVICE_NAME = tnsorahome.support.robotron.de))
 )

Time for the first test. I simply start SQL*Plus using the one alias defined in all four tnsnames.ora files.

C:\Users\marco.mischke>sqlplus pdbadmin/********@tnstest

SQL*Plus: Release 19.0.0.0.0 - Production on Wed May 10 10:47:05 2023
Version 19.15.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.

Last Successful login time: Wed May 10 2023 09:26:24 +02:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

SQL> show con_name

CON_NAME
------------------------------
TNSLOCAL

Obviously my connection gets routed to the “TNSLOCAL” PDB which means, the tnsnames.ora in the current working directory was picked up.

Now I remove this file and try another connection.

C:\Users\marco.mischke>del tnsnames.ora

C:\Users\marco.mischke>sqlplus pdbadmin/********@tnstest

SQL*Plus: Release 19.0.0.0.0 - Production on Wed May 10 10:48:34 2023
Version 19.15.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

SQL> show con_name

CON_NAME
------------------------------
TNSADMIN

Ok, now the tnsnames.ora from the directory pointed to by the TNS_ADMIN environment variable was used, because I am now connected to the “TNSADMI” PDB.

Next step is to unset TNS_ADMIN or, as an alternative, remove that tnsnames.ora file too and try again.

C:\Users\marco.mischke>set TNS_ADMIN=

C:\Users\marco.mischke>set TNS
Die Umgebungsvariable "TNS" ist nicht definiert.

C:\Users\marco.mischke>sqlplus pdbadmin/********@tnstest

SQL*Plus: Release 19.0.0.0.0 - Production on Wed May 10 10:49:32 2023
Version 19.15.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

SQL> show con_name

CON_NAME
------------------------------
TNSREGISTRY

Last but not least, I remove the Registry key for TNS_ADMIN.

C:\Users\marco.mischke>reg delete HKLM\SOFTWARE\Oracle\KEY_OraClient19Home1 /v TNS_ADMIN
Registrierungswert TNS_ADMIN löschen (Ja/Nein)? Ja

C:\Users\marco.mischke>reg query HKLM\SOFTWARE\Oracle\KEY_OraClient19Home1 /v TNS_ADMIN


FEHLER: Der angegebene Registrierungsschlüssel bzw. Wert wurde nicht gefunden.

C:\Users\marco.mischke>sqlplus pdbadmin/********@tnstest

SQL*Plus: Release 19.0.0.0.0 - Production on Wed May 10 10:51:55 2023
Version 19.15.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.16.0.0.0

SQL> show con_name

CON_NAME
------------------------------
TNSORAHOME

So finally I ended up in the “TNSORAHOME” PDB meaning, SQL*plus used the tnsnames.ora in the ORACLE_HOME.

These four tests reveal the search order for the SQL*Net configuration files, especially tnsnames.ora:

  1. Current working directory
  2. Directory pointed to by TNS_ADMIN environment variable
  3. Directory pointed to by TNS_ADMIN registry value
  4. ORACLE_HOME/network/admin

Keep that in mind, esspecially the first point. If your connection fails or ends up in a database that you do not expect, there might be a tnsnames.ora file in your current directory which gets picked up first regardless of any other settings.