Skip to content

ORA-00201: Control File Version Incompatible with ORACLE Version

ORA-00201: Control File Version Incompatible with ORACLE Version

Section titled “ORA-00201: Control File Version Incompatible with ORACLE Version”

Error Text: ORA-00201: control file version [version] incompatible with ORACLE version [version]

This error occurs when the Oracle database control file was created or last updated by a different version of the Oracle software than the one currently being used to start the database. The control file contains version-specific metadata, and Oracle requires version compatibility between the control file and the software binary. This is a critical startup error that prevents the database from opening.

Control File Version Check (at STARTUP)
├── Oracle binary reads control file header
├── Compares control file version stamp with software version
├── If versions are compatible → STARTUP proceeds
├── If control file is older → May require upgrade
├── If control file is newer → Error ORA-00201
└── If control file is from incompatible major version → Error ORA-00201
  • Wrong ORACLE_HOME - Starting the database with binaries from a different Oracle version
  • Incomplete upgrade - Database upgrade started but not finished; control file partially updated
  • Mixed version environments - Multiple Oracle homes on the same server with incorrect PATH or environment
  • Container/Docker version conflicts - Oracle container image version does not match the mounted database files
  • Downgrade attempt - Trying to open a database with an older Oracle version after an upgrade
  • 23ai migration issues - Upgrading from 19c to 23ai without completing all upgrade steps
-- If you can connect to another database or use SQL*Plus without mounting
-- Check the Oracle binary version
SELECT * FROM V$VERSION;
-- Or from the operating system
-- Linux/Unix:
-- $ORACLE_HOME/bin/sqlplus -V
Terminal window
# Check Oracle binary version from the command line
$ORACLE_HOME/bin/sqlplus -V
# Verify which ORACLE_HOME is set
echo $ORACLE_HOME
# Check if multiple Oracle homes exist
cat /etc/oratab
# List all Oracle installations
find / -name "oracle" -type f -path "*/bin/*" 2>/dev/null
Terminal window
# Check control file location from the parameter file (pfile/spfile)
grep -i control_files $ORACLE_HOME/dbs/init${ORACLE_SID}.ora
# Or check the spfile
strings $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora | grep -i control_files
# Verify control files exist and check timestamps
ls -la /path/to/control/files/
# Use the strings command to inspect control file version
strings /path/to/control01.ctl | head -20
Terminal window
# Check current environment
env | grep -i oracle
# Expected output should show consistent versions:
# ORACLE_HOME=/u01/app/oracle/product/23.0.0/dbhome_1
# ORACLE_SID=ORCL
# PATH includes correct ORACLE_HOME/bin
# Check if oraenv is setting the right home
cat /etc/oratab | grep $ORACLE_SID
# Verify the actual binary being used
which sqlplus
which oracle
ls -la $(which sqlplus)
file $ORACLE_HOME/bin/oracle
-- If the database can be mounted (or from a backup of the pfile)
SHOW PARAMETER compatible
-- Or check the parameter file directly
-- grep -i compatible $ORACLE_HOME/dbs/init${ORACLE_SID}.ora
Terminal window
# Check COMPATIBLE parameter from spfile
strings $ORACLE_HOME/dbs/spfile${ORACLE_SID}.ora | grep -i compatible
Terminal window
# Check the alert log for the full error context
# The alert log location depends on diagnostic_dest parameter
tail -100 $ORACLE_BASE/diag/rdbms/${ORACLE_SID,,}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log
# Or for older Oracle versions
tail -100 $ORACLE_HOME/rdbms/log/alert_${ORACLE_SID}.log
# Search for the specific error
grep -A 10 "ORA-00201" $ORACLE_BASE/diag/rdbms/${ORACLE_SID,,}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log

Set Environment to Match the Control File Version

Section titled “Set Environment to Match the Control File Version”
Terminal window
# Check /etc/oratab for available Oracle homes
cat /etc/oratab
# Example output:
# ORCL:/u01/app/oracle/product/19.0.0/dbhome_1:N
# ORCL23:/u01/app/oracle/product/23.0.0/dbhome_1:N
# Set environment to the correct Oracle home
export ORACLE_SID=ORCL
export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1 # Match the DB version
export PATH=$ORACLE_HOME/bin:$PATH
# Verify the version
sqlplus -V
# Start the database
sqlplus / as sysdba
-- Start the database with the correct ORACLE_HOME
STARTUP
Terminal window
# Verify the upgrade status
# Set ORACLE_HOME to the NEW (target) version
export ORACLE_HOME=/u01/app/oracle/product/23.0.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
-- Start the database in upgrade mode
STARTUP UPGRADE
-- Check current version and status
SELECT VERSION_FULL, STATUS FROM V$INSTANCE;
-- Run the upgrade script (for manual upgrade)
@?/rdbms/admin/catupgrd.sql
-- Or use the post-upgrade status check
@?/rdbms/admin/utlu122s.sql
Terminal window
# AutoUpgrade is the supported method for upgrading to 23ai
# Step 1: Download the latest AutoUpgrade JAR
# Available from My Oracle Support or included in 23ai ORACLE_HOME
# Step 2: Create the AutoUpgrade configuration file
cat > /tmp/autoupgrade_config.cfg <<EOF
global.autoupg_log_dir=/u01/autoupgrade/logs
upg1.source_home=/u01/app/oracle/product/19.0.0/dbhome_1
upg1.target_home=/u01/app/oracle/product/23.0.0/dbhome_1
upg1.sid=ORCL
upg1.log_dir=/u01/autoupgrade/logs/ORCL
upg1.upgrade_node=localhost
upg1.run_utlrp=yes
upg1.timezone_upg=yes
EOF
# Step 3: Run AutoUpgrade in analyze mode first
java -jar $ORACLE_HOME/rdbms/admin/autoupgrade.jar \
-config /tmp/autoupgrade_config.cfg \
-mode analyze
# Step 4: Review the analysis report
# Check /u01/autoupgrade/logs/ORCL/ for results
# Step 5: Run the actual upgrade
java -jar $ORACLE_HOME/rdbms/admin/autoupgrade.jar \
-config /tmp/autoupgrade_config.cfg \
-mode deploy
-- Step 1: Generate a CREATE CONTROLFILE script from a backup or trace
-- If the database was previously open, check for a control file backup trace
-- The alert log often contains the CREATE CONTROLFILE command
-- Step 2: Start the database in NOMOUNT mode
STARTUP NOMOUNT
-- Step 3: Execute the CREATE CONTROLFILE statement
-- Adjust paths, database name, and file specifications to match your environment
CREATE CONTROLFILE REUSE DATABASE "ORCL" RESETLOGS ARCHIVELOG
MAXLOGFILES 50
MAXLOGMEMBERS 5
MAXDATAFILES 1024
MAXINSTANCES 8
MAXLOGHISTORY 2048
LOGFILE
GROUP 1 '/u01/oradata/ORCL/redo01.log' SIZE 200M BLOCKSIZE 512,
GROUP 2 '/u01/oradata/ORCL/redo02.log' SIZE 200M BLOCKSIZE 512,
GROUP 3 '/u01/oradata/ORCL/redo03.log' SIZE 200M BLOCKSIZE 512
DATAFILE
'/u01/oradata/ORCL/system01.dbf',
'/u01/oradata/ORCL/sysaux01.dbf',
'/u01/oradata/ORCL/undotbs01.dbf',
'/u01/oradata/ORCL/users01.dbf'
CHARACTER SET AL32UTF8;
-- Step 4: Open the database
ALTER DATABASE OPEN RESETLOGS;
-- Step 5: Add tempfiles back
ALTER TABLESPACE TEMP ADD TEMPFILE '/u01/oradata/ORCL/temp01.dbf' SIZE 500M AUTOEXTEND ON;
Terminal window
# Set environment to the correct Oracle version
export ORACLE_HOME=/u01/app/oracle/product/23.0.0/dbhome_1
export ORACLE_SID=ORCL
export PATH=$ORACLE_HOME/bin:$PATH
-- Start instance in NOMOUNT mode
STARTUP NOMOUNT
-- Connect to RMAN
-- rman target /
-- Restore the control file from backup
RMAN> RESTORE CONTROLFILE FROM AUTOBACKUP;
-- Or from a specific backup piece
RMAN> RESTORE CONTROLFILE FROM '/backup/location/control_backup.bkp';
-- Mount the database
RMAN> ALTER DATABASE MOUNT;
-- Recover the database
RMAN> RECOVER DATABASE;
-- Open with RESETLOGS
RMAN> ALTER DATABASE OPEN RESETLOGS;

Fixing Version Mismatches in Container Environments

Section titled “Fixing Version Mismatches in Container Environments”
Terminal window
# Check the Oracle container image version
docker inspect <container_name> | grep -i oracle
# Verify the database files version matches the container
docker exec -it <container_name> bash -c 'echo $ORACLE_HOME; $ORACLE_HOME/bin/sqlplus -V'
# Common issue: Mounting a 19c database volume into a 23ai container
# Solution: Use the matching container image version
# Example: Use the correct image for your database files
# For 19c database files:
docker run -d --name oracle19c \
-v /data/oracle19c:/opt/oracle/oradata \
container-registry.oracle.com/database/enterprise:19.3.0.0
# For 23ai database files:
docker run -d --name oracle23ai \
-v /data/oracle23ai:/opt/oracle/oradata \
container-registry.oracle.com/database/free:23.6.0.0
# If you need to upgrade database files to match a new container:
# 1. Start with the OLD version container
# 2. Perform the upgrade using AutoUpgrade
# 3. Then switch to the NEW version container
Terminal window
# Check mounted volume contents
docker exec -it <container_name> ls -la /opt/oracle/oradata/
# Check alert log inside the container
docker exec -it <container_name> cat \
/opt/oracle/diag/rdbms/*/*/trace/alert_*.log | tail -50
# Verify ORACLE_HOME consistency
docker exec -it <container_name> bash -c '
echo "ORACLE_HOME: $ORACLE_HOME"
echo "Binary version:"
$ORACLE_HOME/bin/sqlplus -V
echo "Control files:"
strings /opt/oracle/oradata/*/control01.ctl 2>/dev/null | head -5
'
# Create a robust oraenv script
cat > /usr/local/bin/set_oracle_env.sh <<'EOF'
#!/bin/bash
# Usage: source set_oracle_env.sh <ORACLE_SID>
if [ -z "$1" ]; then
echo "Usage: source set_oracle_env.sh <ORACLE_SID>"
return 1
fi
ORACLE_SID=$1
export ORACLE_SID
# Read ORACLE_HOME from oratab
ORACLE_HOME=$(grep "^${ORACLE_SID}:" /etc/oratab | cut -d: -f2)
if [ -z "$ORACLE_HOME" ]; then
echo "ERROR: SID '$ORACLE_SID' not found in /etc/oratab"
return 1
fi
export ORACLE_HOME
# Remove any existing Oracle paths and add the correct one
PATH=$(echo $PATH | tr ':' '\n' | grep -v '/app/oracle/product' | tr '\n' ':')
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
echo "Environment set for $ORACLE_SID"
echo " ORACLE_HOME: $ORACLE_HOME"
echo " Version: $($ORACLE_HOME/bin/sqlplus -V 2>/dev/null | head -1)"
EOF
chmod +x /usr/local/bin/set_oracle_env.sh
-- Run pre-upgrade checks (from the TARGET Oracle home)
-- For 23ai upgrades:
@?/rdbms/admin/preupgrade.jar
-- Check COMPATIBLE parameter (cannot be downgraded once raised)
SHOW PARAMETER compatible
-- Verify current database version
SELECT
VERSION,
VERSION_FULL,
STATUS
FROM V$INSTANCE;
-- Check for invalid objects before upgrade
SELECT
owner,
object_type,
COUNT(*) AS invalid_count
FROM dba_objects
WHERE status = 'INVALID'
GROUP BY owner, object_type
ORDER BY owner, object_type;
-- Check for deprecated/desupported features
SELECT
name,
detected_usages,
first_usage_date,
last_usage_date
FROM dba_feature_usage_statistics
WHERE detected_usages > 0
AND name IN (
'Database Vault',
'Oracle Streams',
'Advanced Replication'
)
ORDER BY name;
-- Verify control file backup exists
SELECT
name,
status,
TO_CHAR(creation_time, 'YYYY-MM-DD HH24:MI:SS') AS created
FROM V$CONTROLFILE;
-- Back up current control file to trace
ALTER DATABASE BACKUP CONTROLFILE TO TRACE AS '/tmp/control_file_backup.sql';
-- Always maintain a control file backup before any version change
-- RMAN automatic control file backup
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
RMAN> CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/cf_%F';
-- Manual control file backup
ALTER DATABASE BACKUP CONTROLFILE TO '/backup/control_backup.ctl';
-- Backup control file to trace (readable SQL script)
ALTER DATABASE BACKUP CONTROLFILE TO TRACE
AS '/backup/create_controlfile.sql'
REUSE NORESETLOGS;
-- Verify backups
SELECT
RECID,
STAMP,
TO_CHAR(COMPLETION_TIME, 'YYYY-MM-DD HH24:MI:SS') AS completed,
STATUS,
CONTROLFILE_TYPE
FROM V$BACKUP_CONTROLFILE_DETAILS
ORDER BY COMPLETION_TIME DESC
FETCH FIRST 5 ROWS ONLY;
Terminal window
# Pre-upgrade checklist
# 1. Document current environment
echo "ORACLE_SID: $ORACLE_SID"
echo "ORACLE_HOME: $ORACLE_HOME"
sqlplus -V
# 2. Back up the control file
sqlplus / as sysdba <<EOF
ALTER DATABASE BACKUP CONTROLFILE TO '/backup/pre_upgrade_control.ctl';
ALTER DATABASE BACKUP CONTROLFILE TO TRACE AS '/backup/pre_upgrade_control.sql';
EOF
# 3. Take a full RMAN backup
rman target / <<EOF
BACKUP DATABASE PLUS ARCHIVELOG;
BACKUP CURRENT CONTROLFILE;
EOF
# 4. Record the COMPATIBLE parameter
sqlplus / as sysdba <<EOF
SHOW PARAMETER compatible
EOF
# 5. For 23ai: Use AutoUpgrade in analyze mode first
java -jar $NEW_ORACLE_HOME/rdbms/admin/autoupgrade.jar \
-config /tmp/autoupgrade.cfg \
-mode analyze
Terminal window
# Add version check to .bash_profile or login scripts
oracle_version_check() {
if [ -n "$ORACLE_HOME" ] && [ -n "$ORACLE_SID" ]; then
BINARY_VER=$($ORACLE_HOME/bin/sqlplus -V 2>/dev/null | grep "Release" | awk '{print $3}')
ORATAB_HOME=$(grep "^${ORACLE_SID}:" /etc/oratab | cut -d: -f2)
if [ "$ORACLE_HOME" != "$ORATAB_HOME" ]; then
echo "WARNING: ORACLE_HOME ($ORACLE_HOME) does not match oratab ($ORATAB_HOME) for SID $ORACLE_SID"
fi
fi
}
# Run the check
oracle_version_check
# Add version validation to container startup scripts
# validate_version.sh - Run before starting the database in a container
#!/bin/bash
BINARY_VERSION=$($ORACLE_HOME/bin/sqlplus -V | grep "Release" | awk '{print $3}' | cut -d. -f1-2)
echo "Oracle binary version: $BINARY_VERSION"
DATAFILE_PATH="/opt/oracle/oradata"
if [ -d "$DATAFILE_PATH" ] && [ "$(ls -A $DATAFILE_PATH 2>/dev/null)" ]; then
echo "Existing database files found. Verify version compatibility before starting."
# Check control file if it exists
CONTROL_FILE=$(find $DATAFILE_PATH -name "control*.ctl" -o -name "control*.dbf" 2>/dev/null | head -1)
if [ -n "$CONTROL_FILE" ]; then
echo "Control file found: $CONTROL_FILE"
echo "Control file timestamp: $(ls -la $CONTROL_FILE)"
fi
else
echo "No existing database files. Fresh installation will proceed."
fi
  • ORA-00205 - Error in identifying control file
  • ORA-00210 - Cannot open the specified control file
  • ORA-00214 - Control file version inconsistent
  • ORA-00600 - Internal error (may occur during failed upgrades)
  • ORA-01034 - Oracle not available (database cannot start)
  1. Check the alert log for the full error message including both version numbers
  2. Verify ORACLE_HOME and ORACLE_SID environment variables
  3. Compare the Oracle binary version with the database version in /etc/oratab
  4. If wrong ORACLE_HOME, set the correct environment and restart
  5. If mid-upgrade, complete the upgrade using AutoUpgrade (23ai) or catupgrd.sql
  6. If the control file is corrupted, restore from RMAN backup or recreate from trace
Terminal window
# Check environment
echo $ORACLE_HOME; echo $ORACLE_SID; $ORACLE_HOME/bin/sqlplus -V; cat /etc/oratab
# Check alert log
tail -50 $ORACLE_BASE/diag/rdbms/${ORACLE_SID,,}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log
# Set correct environment
source /usr/local/bin/oraenv # or manually set ORACLE_HOME and PATH
-- Start in upgrade mode (if upgrade is needed)
STARTUP UPGRADE
-- Back up control file to trace
ALTER DATABASE BACKUP CONTROLFILE TO TRACE AS '/tmp/create_cf.sql';
-- Restore control file from RMAN
-- rman target /
-- RESTORE CONTROLFILE FROM AUTOBACKUP;
  • Always verify ORACLE_HOME before startup - Use oratab and version checks
  • Back up control files before any upgrade - Both binary copy and trace script
  • Use AutoUpgrade for 23ai migrations - It is the only supported upgrade method
  • Keep /etc/oratab updated - Accurate mapping of SIDs to Oracle homes
  • Validate container image versions - Ensure container and data file versions match
  • Never raise COMPATIBLE prematurely - The COMPATIBLE parameter change is irreversible