Skip to main content

How to Fix ORA-28001: The Password Has Expired in Oracle Databases

·6 mins

Introduction #

“ORA-28001: the password has expired” is one of the most common Oracle database errors we see in production environments, especially after system migrations, tech refreshes, or security policy changes.

From the application side, it usually appears as a generic database connection failure. From the operations side, it often shows up during an incident when users cannot log in or key batch jobs stop running.

This guide explains, from a DBA / SRE perspective, how to:

  • Understand what ORA-28001 really means.
  • Safely reset the affected account.
  • Adjust password policies for long-lived service accounts.
  • Prevent the same incident from happening again.

Supported Oracle versions: This guide focuses on the ORA-28001 error and password profile behaviour that are common across supported Oracle Database releases. The steps are written in a version-agnostic way so you can use them as a starting point whether your environment is relatively old or more recent, as long as password profiles and ORA-28001 are available.

What ORA-28001 really means #

A typical error pattern in application logs looks like this:

[2025-02-22 13:40:30 +0000] ERROR: DatabaseError: ORA-28001: the password has expired

On the database side, Oracle evaluates the user profile assigned to the account. If PASSWORD_LIFE_TIME has been exceeded and the password has not been changed within the allowed grace period, the account is marked as expired and new connections fail with ORA-28001.

In many production systems, this affects service accounts used by applications, background jobs, or integration layers rather than human users.

A simple mental model of the error #

At a high level, ORA-28001 is the result of a mismatch between password policy and how service accounts are actually used.

%%{init: {'theme':'base', 'themeVariables': { 'fontSize':'24px'}}}%% sequenceDiagram participant User as Application User participant App as Application participant DB as Oracle Database participant Profile as Password Profile User->>App: HTTP request / job trigger App->>DB: Connect with service account DB->>Profile: Check password life time Profile-->>DB: Password expired DB-->>App: ORA-28001: the password has expired App-->>User: 500 error / login failure

To fix the incident properly, we need to:

  • Restore connectivity quickly and safely.
  • Decide whether the current password policy still makes sense.
  • Put monitoring in place so we see the next expiry before it breaks production.

Prerequisites and safety checks #

Before changing anything in production, ensure:

  • Privileges: You can connect to the database with SYSDBA rights.
  • Access: You can log in as the Oracle software owner on the database server (commonly oracle).
  • Change controls: The change is approved according to your organisation’s process.
  • Sensitive data: New passwords are generated and stored in a secure vault, not in chat logs or emails.

If possible, test the procedure in a non-production environment first.

Step-by-step resolution playbook #

1. Connect to the database as SYSDBA #

Log in to the database server as the Oracle software owner and start SQL*Plus:

su - oracle
sqlplus / as sysdba

If you connect remotely, you can also use:

sqlplus sys@"//db-hostname:1521/DBSERVICE" as sysdba

2. Identify expired user accounts #

List all accounts that are currently expired:

SELECT username,
       account_status,
       expiry_date
FROM   dba_users
WHERE  account_status LIKE '%EXPIRED%'
ORDER  BY expiry_date DESC;

Typical output for a service account might look like this:

USERNAME                       ACCOUNT_STATUS       EXPIRY_DATE
------------------------------ -------------------- ----------
APP_USER                       EXPIRED              22-FEB-25

Confirm which account is used by the affected application before proceeding.

3. Reset the password for the affected user #

Reset the password for the service account. Replace APP_USER and the password value with your actual account name and a secure, policy-compliant password.

ALTER USER APP_USER IDENTIFIED BY "New_Strong_Password_2025!";

Expected response:

User altered.

Update your application configuration or secret management system to use the new password.

4. Decide on password policy for service accounts #

This is where many environments get into trouble. Human users and long-lived service accounts usually deserve different password policies.

You have several options; choose the one that matches your security requirements.

Option A: Extend password life in the default profile #

If your organisation is comfortable with a long but finite password life time, you can increase it globally:

ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 365;

This sets the life time to 365 days for all users in the DEFAULT profile.

Option B: Create a dedicated profile for service accounts #

A more controlled approach is to:

  1. Create a dedicated profile for service accounts.
  2. Assign only the necessary accounts to this profile.

Example:

CREATE PROFILE SERVICE_ACCOUNTS LIMIT
  PASSWORD_LIFE_TIME UNLIMITED
  PASSWORD_REUSE_MAX 20
  FAILED_LOGIN_ATTEMPTS 10
  PASSWORD_LOCK_TIME 1;

ALTER USER APP_USER PROFILE SERVICE_ACCOUNTS;

This removes automatic expiry for APP_USER while still keeping other safeguards in place (lockout on repeated failures, reuse limits, and so on).

Security note: If you set PASSWORD_LIFE_TIME to UNLIMITED, you should compensate with strong password creation, restricted access, and regular manual reviews.

Option C: Keep expiry but monitor it #

If policy requires regular rotation, keep PASSWORD_LIFE_TIME but:

  • Monitor upcoming expiry dates using scheduled queries on dba_users.
  • Send alerts to the operations team when key service accounts are within the grace period.
  • Integrate password rotation into your regular maintenance window.

5. Verify account status #

After resetting the password and adjusting profiles, confirm that the account is now open:

SELECT username,
       account_status,
       expiry_date,
       profile
FROM   dba_users
WHERE  username = 'APP_USER';

Expected output:

USERNAME                       ACCOUNT_STATUS       EXPIRY_DATE PROFILE
------------------------------ -------------------- ---------- -----------------
APP_USER                       OPEN                 22-FEB-25   SERVICE_ACCOUNTS

ACCOUNT_STATUS should be OPEN. If it is LOCKED or EXPIRED(GRACE), investigate further before proceeding.

6. Exit SQL*Plus #

Once changes are verified, exit the SQL*Plus session:

EXIT;

7. Restart the application service #

Most applications maintain connection pools. They need to be restarted so that new connections use the updated credentials.

On a typical Linux system using systemd:

sudo systemctl restart app-backend.service
sudo systemctl status app-backend.service

Confirm that the service is active (running) and that no new ORA-28001 errors appear in the logs.

8. Monitor after the change #

For the next few hours or days:

  • Watch application logs for any remaining authentication errors.
  • Check database alert logs for related messages.
  • Validate that key application workflows (login, reporting, batch jobs) are functioning normally.

Visual overview: incident response flow #

The following diagram summarises the end-to-end flow from detection to resolution.

%%{init: {'theme':'base', 'themeVariables': { 'fontSize':'18px'}}}%% flowchart TD Detect["Detect ORA-28001 in logs / monitoring"] Triage["Triage: confirm affected application and DB user"] Connect["Connect as SYSDBA via SQL*Plus"] ListExpired["List expired users from dba_users"] ResetPassword["Reset password for service account"] AdjustPolicy["Adjust password policy / profile if needed"] RestartApp["Restart application service / connection pool"] Monitor["Monitor logs, metrics, and user journeys"] Detect --> Triage --> Connect --> ListExpired --> ResetPassword --> AdjustPolicy --> RestartApp --> Monitor

This is the pattern we use to turn a one-off incident into a repeatable, auditable operational runbook.

Hardening and prevention checklist #

Once the immediate incident is resolved, invest a bit more time to reduce the chance of recurrence:

  • Document service accounts: Maintain an inventory of all application database users, their profiles, and owning systems.
  • Segment profiles: Use dedicated profiles for service accounts versus human users.
  • Monitor expiry proactively: Schedule a job to alert on upcoming expiries for critical accounts.
  • Centralise secrets: Store database passwords in a central secrets manager instead of local config files.
  • Review regularly: Include password policies and account status in your quarterly or semi-annual security reviews.
  • Test after changes: After any database or OS patching, proactively test critical application paths.

Consistent basic hygiene turns ORA-28001 from a high-severity incident into a routine maintenance task.

How SYNKEE can help #

SYNKEE is a Singapore-based engineering team focused on:

  • Designing and operating reliable application and database platforms.
  • Building practical runbooks and automation for day-to-day operations.
  • Helping organisations in Southeast Asia harden their Oracle, middleware, and supporting infrastructure.

If you would like support in turning your incident history into robust SOPs and automation, or need a review of your current Oracle database operations, contact us to discuss how we can help.