ORA-01017 — Password Rotation Broke Database Links
Nightly ETL fails with ORA-06512; deepest error ORA-01017 from stale DB link passwords.
20+ years shipping production Java in banking & fintech. Every example here is drawn from a real system.
- ORA-01017 means the Oracle server rejected the credentials — the username does not exist, the password is wrong, or the authentication method is misconfigured
- The error fires at the authentication layer before any SQL executes — no session is created, no queries run
- Common causes: wrong password, case-sensitive password mismatch (11g+ default), expired password, profile-driven lockout, and stale database link credentials
- Unlike ORA-28000 (account is locked) or ORA-28001 (password has expired), ORA-01017 is deliberately vague — it does not tell you WHICH credential component failed, because confirming whether a username exists would be an information disclosure vulnerability
- Production insight: roughly 40% of ORA-01017 incidents in post-migration environments are caused by case-sensitivity mismatches or password file desynchronization — not genuinely wrong passwords
- Biggest mistake: assuming the username is wrong when the real issue is a case-sensitive password that was stored as uppercase via ALTER USER without double quotes, or an external authentication fallback masking a password mismatch
ORA-01017 is Oracle saying: "I do not recognize these credentials." The server received a username and password but cannot match them to a valid database account. Unlike application-layer errors, this failure happens before any SQL executes — the connection is rejected at the authentication handshake, and no session is established. The error is intentionally vague about the specific root cause: Oracle does not distinguish between a nonexistent username, a wrong password, an expired password, or a locked account in the error message itself. This vagueness is a security feature — Oracle refuses to confirm whether a given username exists in the database, which prevents attackers from enumerating valid accounts by testing usernames one at a time.
ORA-01017: invalid username/password; logon denied is Oracle's authentication rejection error. It fires when the server cannot validate the supplied credentials against its user store — whether that store is the data dictionary, a password file, an LDAP directory, or an OS account mapping. The error is a hard stop: no session is created, no queries execute, and at the direct connection level, no ORA-06512 stack trace is generated because no PL/SQL was ever invoked.
However, ORA-01017 frequently appears inside ORA-06512 stack traces in production systems when stored procedures use database links with embedded credentials. A procedure that queries a remote database via CREATE DATABASE LINK ... CONNECT TO user IDENTIFIED BY pass will raise ORA-01017 at the remote authentication layer if the embedded credentials are wrong — typically because the remote password was rotated but the link definition still holds the old password. The error propagates through the PL/SQL call stack as ORA-06512 entries, and engineers see the stack trace without immediately recognizing that the root cause is an authentication failure on a database link, not a code defect.
The diagnostic path diverges depending on context. Direct connection failures (an application or tool cannot authenticate) require checking the username, password, password case sensitivity, account status, profile policies, and authentication method. Database link failures (a link query raises ORA-01017 inside a procedure) require checking the link's CONNECT TO clause, the remote database's account status, and whether the remote password was recently rotated. Confusing the two — or checking the wrong credential store — is the most common reason this error wastes hours.
Why ORA-01017 Is a Password-Rotation Landmine
ORA-01017 means the Oracle database rejected a login because the username or password is invalid. The core mechanic: Oracle compares the supplied credential hash against the stored hash in the data dictionary. If they don't match, the connection fails immediately — no retry, no fallback. This is a hard authentication failure, not a transient network error.
In practice, ORA-01017 surfaces most often in fixed-credential contexts: database links, connection pools, and scheduled jobs. A database link stores the remote username and password as encrypted text in the data dictionary. When the remote password changes, every link that uses those credentials becomes stale. The link doesn't refresh automatically — it keeps sending the old password until someone manually updates it. The same applies to JDBC connection pools with hardcoded credentials.
Use this knowledge to audit any system that stores credentials outside the application's runtime configuration. If your team rotates database passwords quarterly, every database link, every cron job, and every connection pool must be updated in lockstep. One missed link causes a production outage that looks like a network issue but is actually a credential mismatch. Treat ORA-01017 as a design smell: it often indicates credential duplication that should be replaced with a centralized secrets manager or token-based authentication.
Oracle Authentication: How ORA-01017 Is Raised
Oracle authentication happens at the session establishment layer, before any SQL statement executes. The client initiates a connection through the TNS listener, which redirects the client to a dedicated server process (or a shared server dispatcher). The server process challenges the client for credentials. The client sends the username and a cryptographic hash of the password. The server computes the same hash from its stored password verifier and compares. If the hashes match, a session is created and the client can begin executing SQL. If they do not match, ORA-01017 is raised and the connection is rejected.
Oracle maintains password verifiers (hashes) in the SYS.USER$ table within the data dictionary. The hashing algorithm depends on the Oracle version and the SQLNET.ALLOWED_LOGON_VERSION_SERVER and SQLNET.ALLOWED_LOGON_VERSION_CLIENT parameters: Oracle 10g used a DES-based hash, Oracle 11g added a SHA-1-based hash with case sensitivity, and Oracle 12c and later use SHA-2/SHA-512 with salt. The client and server negotiate which verifier to use during the authentication handshake — if the client is older and only supports the 10g verifier but the server has removed 10g verifiers (12c+ default behavior), the authentication fails with ORA-01017.
The password file (orapwSID) is a separate credential store used exclusively for SYSDBA and SYSOPER connections when REMOTE_LOGIN_PASSWORDFILE is set to EXCLUSIVE or SHARED. Normal connections never consult the password file — they authenticate against the data dictionary. This dual-store model is the root cause of a common ORA-01017 variant: ALTER USER changes the data dictionary hash but does not update the password file, so SYSDBA connections fail while normal connections succeed.
The error message is deliberately identical for all failure modes: wrong username, wrong password, expired password, locked account (in some configurations), and authentication method mismatch. Oracle does not want to confirm whether a username exists, because that information would allow an attacker to enumerate valid accounts. The diagnostic burden falls on the DBA to check each possible cause independently.
- Data dictionary (SYS.USER$): standard password authentication — used for normal connections (sqlplus user/pass@db)
- Password file (orapwSID): SYSDBA and SYSOPER authentication — used for privileged connections (sqlplus / as sysdba remotely)
- External authentication: OS accounts (ops$), Kerberos, LDAP, RADIUS — bypasses password entirely but can fall back to password auth on failure
- ALTER USER changes the data dictionary hash but does NOT update the password file — SYSDBA can fail while normal connections succeed
- SEC_CASE_SENSITIVE_LOGON controls whether password comparison includes case (11g+ default: TRUE)
- SQLNET.ALLOWED_LOGON_VERSION controls which hash algorithms are accepted — older clients may be rejected after upgrades
Case-Sensitive Passwords: The 11g+ Gotcha
Oracle 11g introduced case-sensitive passwords by default. The parameter SEC_CASE_SENSITIVE_LOGON controls this behavior. When set to TRUE (the default since 11g), the password verifier stored in the data dictionary includes case information: 'MyPassword' and 'mypassword' produce different hashes and are treated as different passwords.
This causes ORA-01017 in two common scenarios. First, applications or scripts that convert the password to uppercase before sending it to Oracle — a practice that was harmless in Oracle 10g — will fail if the actual password contains lowercase characters. Second, migrations from Oracle 10g to 11g or later can break all connections if the passwords were originally set without case awareness.
The mechanism is straightforward: the password hash stored in SYS.USER$ is computed from the exact character sequence including case. The client computes the same hash from the password the user supplies. If the user supplies 'Password123' but the stored hash was computed from 'PASSWORD123' (because ALTER USER was run without double quotes, which causes Oracle to uppercase the value), the hashes do not match and ORA-01017 is raised.
The subtlety that catches most engineers: ALTER USER app_user IDENTIFIED BY MyPassword (without double quotes) stores the password as MYPASSWORD in uppercase. This is because Oracle treats the unquoted identifier as a regular SQL identifier and uppercases it. ALTER USER app_user IDENTIFIED BY "MyPassword" (with double quotes) stores the password as MyPassword with the exact case preserved. The quoting behavior during password creation determines the case of the stored verifier — and the user must supply the same case when connecting.
Oracle 12c and later further complicated this by introducing the SQLNET.ALLOWED_LOGON_VERSION_SERVER parameter, which controls which password verifiers are accepted. If set to 12 or 12a, only SHA-2 verifiers are accepted, and clients that only support the older 10g DES-based verifier are rejected with ORA-01017. After an upgrade, if the user's password was never reset (so only the old verifier exists), authentication fails even though the password itself is correct.
- ALTER USER ... IDENTIFIED BY password (no quotes): stores UPPERCASE — the user must authenticate with UPPERCASE
- ALTER USER ... IDENTIFIED BY "Password" (with quotes): stores exact case — the user must authenticate with exact case
- Applications that uppercase the password string before sending it to Oracle will fail if the stored verifier was set with mixed case
- Migration from 10g to 11g+ can break connections if passwords were set without quotes (uppercase) but clients send lowercase
- After upgrading to 12c+, reset all passwords to generate SHA-2 verifiers — old verifiers may be rejected by ALLOWED_LOGON_VERSION_SERVER
- Disabling SEC_CASE_SENSITIVE_LOGON weakens security — fix the client and password case instead
Account Lockout and Password Expiry
Oracle profiles enforce password policies that control login behavior: maximum failed login attempts before lockout, password lifetime before expiry, lockout duration, grace period after expiry, and password reuse restrictions. When any policy is violated, the account status changes from OPEN to a non-OPEN state, and all connection attempts receive ORA-01017 (or in some cases ORA-28000 for locked accounts, depending on the Oracle version and configuration).
The profile parameter FAILED_LOGIN_ATTEMPTS controls automatic lockout after consecutive failed login attempts. The DEFAULT profile ships with FAILED_LOGIN_ATTEMPTS set to 10 in most Oracle versions. After 10 consecutive wrong-password attempts, the account status becomes LOCKED(TIMED) for the duration specified by PASSWORD_LOCK_TIME (default: 1 day). During the lock period, even correct credentials are rejected.
The profile parameter PASSWORD_LIFE_TIME controls password expiry. After the specified number of days since the last password change, the password expires. The account status transitions to EXPIRED(GRACE) for PASSWORD_GRACE_TIME days, during which the user can still connect but Oracle prompts for a password change. After the grace period, the status becomes EXPIRED and all connections are rejected until the DBA resets the password.
The most dangerous production scenario is a shared service account with a low FAILED_LOGIN_ATTEMPTS value. If one misconfigured application instance sends the wrong password 10 times — perhaps because a configuration file has a stale password — the account locks for all consumers. Every other application, ETL job, and reporting query that uses the same account is blocked until the lockout expires or the DBA manually unlocks it. This cascading lockout is common in microservices environments and connection pool configurations where multiple processes share a single database account.
The fix has two parts: immediate (unlock the account) and permanent (prevent recurrence). For service accounts, create a dedicated profile with FAILED_LOGIN_ATTEMPTS set to UNLIMITED and PASSWORD_LIFE_TIME set to UNLIMITED. For human user accounts, keep the limits but ensure the lockout duration (PASSWORD_LOCK_TIME) is reasonable — 1/1440 (one minute) is often more appropriate than the default 1 day for environments with automated retry logic.
- OPEN: normal state — connections allowed with correct credentials
- LOCKED(TIMED): auto-locked after FAILED_LOGIN_ATTEMPTS consecutive failures — auto-unlocks after PASSWORD_LOCK_TIME, or unlock manually with ALTER USER ACCOUNT UNLOCK
- LOCKED: manually locked by DBA — only unlocked manually with ALTER USER ACCOUNT UNLOCK
- EXPIRED(GRACE): password exceeded PASSWORD_LIFE_TIME — user can still connect but must change password within PASSWORD_GRACE_TIME days
- EXPIRED: grace period ended — all connections rejected until DBA resets with ALTER USER IDENTIFIED BY
- EXPIRED & LOCKED: both conditions — must both unlock AND reset the password
Database Link ORA-01017: Stale Credentials After Password Rotation
Database links store credentials statically in the CONNECT TO ... IDENTIFIED BY clause at creation time. The password embedded in the link definition is a frozen snapshot — it is never automatically updated when the remote database password changes. When the remote password is rotated, the link still authenticates with the old password, and every query through the link raises ORA-01017.
This is the most common cause of ORA-01017 in production environments with password rotation policies. The pattern repeats every rotation cycle: the security team rotates the remote password, the database links still hold the old password, the nightly ETL or reporting pipeline fails with ORA-01017 inside ORA-06512 stacks, and the team spends hours checking the remote account status (which is OPEN and healthy) before realizing the link credentials are stale.
There is no ALTER DATABASE LINK command to update the password. The link must be dropped and recreated with the new password. This means the password rotation process must include an explicit step to enumerate all database links that reference the rotated account, drop each link, and recreate it with the new password. Failing to include this step guarantees an ORA-01017 incident on the next execution of any procedure that uses the link.
For environments that rotate passwords frequently, Oracle Wallet (External Password Store) can centralize credentials outside the link definition. The link is created with CONNECT TO user IDENTIFIED BY VALUES ':wallet_entry' (or simply without an IDENTIFIED BY clause if the wallet is configured for the connect string). Password updates are made to the wallet, and the link inherits the new password without DDL changes. However, wallet configuration adds operational complexity and must be managed carefully in RAC and Data Guard environments.
The immediate diagnostic for database link ORA-01017 is to query USER_DB_LINKS or DBA_DB_LINKS, identify the link's username and host (TNS alias), and test the credentials directly against the remote database. If direct authentication with the same username and password succeeds, the link definition has a different (older) password.
- Database links store a static copy of the password at creation time — they never inherit password changes from the remote database
- There is no ALTER DATABASE LINK command to update the password — you must DROP and CREATE the link
- ORA-01017 inside an ORA-06512 stack trace is the telltale sign of stale database link credentials
- Password rotation runbooks must include a step to enumerate, drop, and recreate all affected database links
- Test every link after rotation with SELECT 1 FROM dual@link_name before closing the rotation ticket
- Consider Oracle Wallet (External Password Store) for environments with frequent rotation cycles
Password File and SYSDBA Authentication
SYSDBA and SYSOPER connections use the password file (orapwSID) as their credential store, not the data dictionary. When REMOTE_LOGIN_PASSWORDFILE is set to EXCLUSIVE or SHARED, the password file is consulted for privileged connections. If the password file contains a different hash than the one computed from the supplied password, ORA-01017 is raised — even though the data dictionary password (used for normal connections) is correct.
The password file is a binary file located at $ORACLE_HOME/dbs/orapwSID on Linux or %ORACLE_HOME%\database\PWDsid.ora on Windows. It stores the username and password hash for users who have been granted SYSDBA or SYSOPER privileges. The critical detail is that ALTER USER does not automatically update the password file. When a DBA runs ALTER USER sys IDENTIFIED BY newpass, the data dictionary hash in SYS.USER$ is updated, but the password file retains the old hash. SYSDBA connections using the password file still authenticate against the old hash and fail.
The fix is to regenerate the password file using the orapwd utility after any password change for a SYSDBA-privileged user. In Oracle 12.2 and later, ALTER USER for the SYS user does update the password file automatically when REMOTE_LOGIN_PASSWORDFILE = EXCLUSIVE and the password file is in the default location. However, this automatic update does not work for non-SYS users with SYSDBA grants, for SHARED password files, or when the password file is stored in a non-default location.
In RAC environments, the password file must be identical on every node. After regenerating the file on one node, it must be copied to all other nodes — or the password file must be stored in ASM (Oracle 12c+), which provides automatic sharing across all nodes. A common production failure is: the DBA regenerates the password file on node 1, SYSDBA works on node 1, but SYSDBA fails on nodes 2 and 3 because they still have the old file.
In Data Guard environments, the password file must be synchronized between the primary and standby databases. If the primary's password file is updated but the standby's is not, a switchover or failover to the standby will result in ORA-01017 for all SYSDBA connections.
- Normal connections (sqlplus user/pass@db): authenticate against the data dictionary (SYS.USER$) — the password file is not consulted
- SYSDBA/SYSOPER connections (sqlplus sys/pass@db as sysdba): authenticate against the password file (orapwSID) — the data dictionary may not be consulted
- ALTER USER changes the data dictionary hash — it does NOT automatically update the password file in most configurations
- After changing a SYSDBA user's password, regenerate the password file with orapwd and distribute to all RAC/Data Guard nodes
- In RAC, the password file must be identical on every node — or store it in ASM for automatic synchronization
- In Data Guard, the standby's password file must match the primary's — or switchover/failover breaks SYSDBA auth
External Authentication Fallback Failures
Oracle supports multiple external authentication methods: OS authentication (ops$ accounts on Linux, NTS on Windows), Kerberos, LDAP, and RADIUS. When external authentication is configured as the primary method but the external credential check fails, Oracle may silently fall back to password authentication. If the password is also wrong — or the user does not have a database password at all — ORA-01017 is raised. The error message gives no indication that an external authentication attempt was made and failed before the password fallback.
The sqlnet.ora parameter SQLNET.AUTHENTICATION_SERVICES controls which authentication methods are active. On Windows, the default value is (NTS), which enables Windows domain authentication. On Linux, the default is typically (NONE) or unset, which means password authentication only. If the parameter includes multiple methods, Oracle tries each in order.
The most confusing scenario is: a DBA connects with sqlplus / as sysdba on the database server and succeeds (OS authentication works because the OS user matches the oracle account). They assume the password is therefore correct. But a remote application connecting with sqlplus user/pass@DB fails with ORA-01017 because it uses password authentication, and the password in the connection string does not match the data dictionary hash. OS authentication and password authentication are completely independent paths — success in one does not prove the other will work.
Another common scenario is ops$ accounts. On Linux, if SQLNET.AUTHENTICATION_SERVICES includes BEQ, Oracle maps the OS username to a database user named OPS$<osuser>. If the OS user is 'oracle', Oracle looks for a database user named OPS$ORACLE. If this user does not exist in the database, the OS authentication fails silently and Oracle falls back to password authentication — which may also fail, producing ORA-01017 with no indication that the real problem is a missing ops$ account.
The diagnostic approach is to determine exactly which authentication method the failing connection is using. Check SQLNET.AUTHENTICATION_SERVICES in the sqlnet.ora that the failing process reads (not the DBA's sqlnet.ora). If external authentication is configured, verify the external credential source (OS account, Kerberos ticket, LDAP bind). If password authentication is the intended method, set SQLNET.AUTHENTICATION_SERVICES = (NONE) to disable external methods and force password-only authentication.
- sqlplus / as sysdba succeeding does NOT prove that password authentication works — it uses OS authentication, which is a completely separate code path
- Check SQLNET.AUTHENTICATION_SERVICES to determine which auth methods are active for the failing process
- If external auth fails, Oracle may silently fall back to password auth — but only if the password is also correct does the connection succeed
- On Windows, NTS is often the default — remove it from AUTHENTICATION_SERVICES to force password-only auth
- ops$ accounts must exist in the database with the exact OS username — OS auth fails silently if the mapping is missing
- Test the exact authentication method your application uses — do not assume one works because a different method succeeds
Password Rotation Broke All Database Links — 4 Hours of Silent ETL Failures
- Password rotation must include database link credential updates — links store a static copy of the password that is never automatically updated
- ORA-01017 inside an ORA-06512 stack trace almost always means stale database link credentials — check the link's CONNECT TO clause before investigating the remote account
- Post-rotation verification must test every database link, not just direct connections — the link uses a different credential store than the connection pool
- Database links have no ALTER command for passwords — they must be dropped and recreated, which means the rotation runbook must include the full DDL
- There is no shortcut: if you rotate passwords without updating links, you will hit ORA-01017 every rotation cycle
Key takeaways
Common mistakes to avoid
6 patternsAssuming the username is wrong when the password is wrong
Setting passwords with ALTER USER without double quotes and expecting mixed-case authentication
Not updating database links after password rotation
Not regenerating the password file after changing a SYSDBA account password
Using a low FAILED_LOGIN_ATTEMPTS value for shared service accounts
Testing OS authentication (sqlplus /) and concluding that password authentication works
Interview Questions on This Topic
What causes ORA-01017 and how do you diagnose it?
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Every example here is drawn from a real system.
That's PL/SQL. Mark it forged?
12 min read · try the examples if you haven't