Skip to content

ORA-19815 Flash Recovery Area Full - Backup Storage Management Guide

ORA-19815: WARNING: db_recovery_file_dest_size is 100% used

Section titled “ORA-19815: WARNING: db_recovery_file_dest_size is 100% used”

Error Text: ORA-19815: WARNING: db_recovery_file_dest_size of nnnn bytes is 100.00% used, and has 0 remaining bytes available.

This critical warning indicates that the Flash Recovery Area (FRA) has reached maximum capacity. While initially appearing as a warning, ORA-19815 can quickly escalate to database-stopping errors when archive logs cannot be created, potentially halting all database transactions.

Flash Recovery Area (FRA)
├── Archive Logs (*.arc)
├── RMAN Backups
│ ├── Database Backups
│ ├── Archive Log Backups
│ ├── Control File Backups
│ └── SPFILE Backups
├── Flashback Logs
├── Control File Autobackups
└── Multiplexed Control Files
  1. Archive logs created first priority
  2. RMAN backups stored based on retention policy
  3. Obsolete files marked for deletion
  4. Space pressure triggers automatic cleanup
  5. Full FRA prevents new archive logs → database hang
  • FRA configured too small for workload
  • High transaction volume generating excessive archive logs
  • Large database requiring more backup space
  • Inadequate capacity planning
  • RMAN retention policy too long
  • Backups not being deleted after successful completion
  • Failed RMAN DELETE commands
  • Manual files consuming FRA space
  • High redo generation rate
  • Long-running transactions
  • Archive log backup failures
  • Network issues preventing archive log deletion
  • Archive log deletion policy misconfigured
  • RMAN crosscheck not running regularly
  • Manual cleanup scripts not executing
  • Monitoring alerts not configured
-- FRA space usage summary
SELECT
space_limit/1024/1024/1024 as size_gb,
space_used/1024/1024/1024 as used_gb,
space_reclaimable/1024/1024/1024 as reclaimable_gb,
number_of_files,
ROUND((space_used/space_limit)*100, 2) as pct_used
FROM v$recovery_file_dest;
-- FRA configuration
SHOW PARAMETER db_recovery_file_dest;
SHOW PARAMETER db_recovery_file_dest_size;
-- Detailed FRA file breakdown
SELECT
file_type,
COUNT(*) as file_count,
ROUND(SUM(percent_space_used), 2) as pct_space_used,
ROUND(SUM(percent_space_reclaimable), 2) as pct_reclaimable,
ROUND(SUM(bytes)/1024/1024/1024, 2) as size_gb
FROM v$recovery_area_usage
GROUP BY file_type
ORDER BY SUM(bytes) DESC;
-- Archive log generation rate
SELECT
TO_CHAR(first_time, 'YYYY-MM-DD HH24') as hour,
COUNT(*) as logs_generated,
ROUND(SUM(blocks * block_size)/1024/1024/1024, 2) as gb_generated,
ROUND(AVG(blocks * block_size)/1024/1024, 2) as avg_log_size_mb
FROM v$archived_log
WHERE first_time > SYSDATE - 7
GROUP BY TO_CHAR(first_time, 'YYYY-MM-DD HH24')
ORDER BY hour DESC;
-- Current archive log status
SELECT
dest_name,
status,
destination,
error
FROM v$archive_dest
WHERE status != 'INACTIVE';
-- Archive log space projection
WITH hourly_generation AS (
SELECT AVG(gb_per_hour) as avg_gb_per_hour
FROM (
SELECT
TO_CHAR(first_time, 'YYYY-MM-DD HH24') as hour,
SUM(blocks * block_size)/1024/1024/1024 as gb_per_hour
FROM v$archived_log
WHERE first_time > SYSDATE - 3
GROUP BY TO_CHAR(first_time, 'YYYY-MM-DD HH24')
)
)
SELECT
avg_gb_per_hour,
avg_gb_per_hour * 24 as gb_per_day,
avg_gb_per_hour * 24 * 7 as gb_per_week
FROM hourly_generation;
-- Recent RMAN backup status
SELECT
session_key,
input_type,
status,
start_time,
end_time,
input_bytes/1024/1024/1024 as input_gb,
output_bytes/1024/1024/1024 as output_gb,
compression_ratio
FROM v$rman_backup_job_details
WHERE start_time > SYSDATE - 7
ORDER BY start_time DESC;
-- RMAN configuration
SELECT name, value
FROM v$rman_configuration
ORDER BY name;
-- Obsolete backups that can be deleted
RMAN TARGET /
LIST EXPIRED BACKUP;
LIST EXPIRED ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
EXIT;
Terminal window
# Find largest files in FRA
FRA_DEST=$(sqlplus -s / as sysdba <<< "SELECT value FROM v\$parameter WHERE name='db_recovery_file_dest';" | grep -v '^$' | tail -1)
echo "FRA Location: $FRA_DEST"
echo ""
echo "Largest files in FRA:"
find "$FRA_DEST" -type f -exec ls -lh {} \; | sort -k5 -hr | head -20
echo ""
echo "Space usage by directory:"
du -sh "$FRA_DEST"/*
echo ""
echo "File count by type:"
find "$FRA_DEST" -name "*.arc" | wc -l && echo "Archive logs"
find "$FRA_DEST" -name "*.bkp" | wc -l && echo "Backup pieces"
find "$FRA_DEST" -name "*.log" | wc -l && echo "Flashback logs"
-- Check current size and usage
SELECT
ROUND(space_limit/1024/1024/1024, 2) as current_size_gb,
ROUND(space_used/1024/1024/1024, 2) as used_gb,
ROUND((space_used/space_limit)*100, 2) as pct_used
FROM v$recovery_file_dest;
-- Increase FRA size (adjust based on available disk space)
ALTER SYSTEM SET db_recovery_file_dest_size = 50G SCOPE = BOTH;
-- Verify the change
SHOW PARAMETER db_recovery_file_dest_size;
-- Check new usage percentage
SELECT
ROUND(space_limit/1024/1024/1024, 2) as new_size_gb,
ROUND(space_used/1024/1024/1024, 2) as used_gb,
ROUND((space_used/space_limit)*100, 2) as new_pct_used
FROM v$recovery_file_dest;

Solution 2: Clean Up Obsolete Files with RMAN

Section titled “Solution 2: Clean Up Obsolete Files with RMAN”
#!/bin/bash
# rman_cleanup.sh - Emergency FRA cleanup
ORACLE_SID=${1:-ORCL}
export ORACLE_SID
echo "Starting RMAN cleanup for $ORACLE_SID..."
rman target / << EOF
# Delete expired and obsolete backups
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
DELETE NOPROMPT OBSOLETE;
# Report current space usage
REPORT OBSOLETE;
REPORT NEED BACKUP;
# Delete old archive logs (keep last 2 days)
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-2';
EXIT;
EOF
echo "RMAN cleanup completed"
# Check FRA usage after cleanup
sqlplus -s / as sysdba << EOF
SET PAGESIZE 0 FEEDBACK OFF
SELECT 'FRA Usage After Cleanup: ' || ROUND((space_used/space_limit)*100, 2) || '%'
FROM v\$recovery_file_dest;
EXIT;
EOF

Manual RMAN Commands for Emergency Cleanup

Section titled “Manual RMAN Commands for Emergency Cleanup”
-- Connect to RMAN
RMAN TARGET /
-- Crosscheck to identify missing files
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
-- Delete expired entries
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
-- Delete obsolete backups based on retention policy
DELETE NOPROMPT OBSOLETE;
-- Force delete old archive logs (emergency only)
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-1'; -- Keep last 24 hours
-- Check what can be deleted safely
REPORT OBSOLETE;
LIST ARCHIVELOG ALL;
-- Delete specific archive logs by sequence (if needed)
DELETE NOPROMPT ARCHIVELOG FROM SEQUENCE 1000 UNTIL SEQUENCE 1500;
EXIT;

Solution 3: Move Files to Alternative Location

Section titled “Solution 3: Move Files to Alternative Location”
#!/bin/bash
# move_archive_logs.sh - Temporary archive log relocation
ORACLE_SID=${1:-ORCL}
FRA_DEST=$(sqlplus -s / as sysdba <<< "SELECT value FROM v\$parameter WHERE name='db_recovery_file_dest';" | grep -v '^$' | tail -1)
TEMP_LOCATION=${2:-/tmp/archive_backup}
echo "Moving archive logs from FRA to temporary location..."
echo "FRA: $FRA_DEST"
echo "Temp: $TEMP_LOCATION"
# Create temporary directory
mkdir -p "$TEMP_LOCATION"
# Find and move older archive logs (keep last 24 hours)
find "$FRA_DEST" -name "*.arc" -mtime +1 -exec mv {} "$TEMP_LOCATION/" \;
echo "Moved archive logs to $TEMP_LOCATION"
echo "Files moved: $(ls -1 $TEMP_LOCATION/*.arc 2>/dev/null | wc -l)"
# Update RMAN catalog
rman target / << EOF
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
EXIT;
EOF
echo "Archive log move completed"
-- Option 1: Change FRA location entirely
ALTER SYSTEM SET db_recovery_file_dest = '/new/larger/location' SCOPE = BOTH;
-- Option 2: Add additional archive destinations
ALTER SYSTEM SET log_archive_dest_2 = 'LOCATION=/additional/archive/location' SCOPE = BOTH;
ALTER SYSTEM SET log_archive_dest_state_2 = ENABLE SCOPE = BOTH;
-- Connect to RMAN and configure retention
RMAN TARGET /
-- Set appropriate retention policy
CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
-- OR for specific backup counts:
-- CONFIGURE RETENTION POLICY TO REDUNDANCY 2;
-- Configure backup optimization
CONFIGURE BACKUP OPTIMIZATION ON;
CONFIGURE CONTROLFILE AUTOBACKUP ON;
CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVICE TYPE DISK TO '/backup/location/%F';
-- Configure compression for space efficiency
CONFIGURE COMPRESSION ALGORITHM 'MEDIUM'; -- Oracle 12c+
CONFIGURE DEVICE TYPE DISK PARALLELISM 4;
-- Enable automatic deletion of files
CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY;
-- OR for non-standby environments:
-- CONFIGURE ARCHIVELOG DELETION POLICY TO BACKED UP 1 TIMES TO DISK;
-- View current configuration
SHOW ALL;
EXIT;
#!/bin/bash
# automated_backup_cleanup.sh - Daily FRA maintenance
ORACLE_SID=${1:-ORCL}
RETENTION_DAYS=${2:-7}
LOG_FILE="/var/log/oracle/fra_cleanup_${ORACLE_SID}.log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
echo "========================================"
echo "FRA Cleanup started: $(date)"
echo "Oracle SID: $ORACLE_SID"
echo "Retention: $RETENTION_DAYS days"
echo "========================================"
export ORACLE_SID
# Check FRA usage before cleanup
echo "FRA usage before cleanup:"
sqlplus -s / as sysdba << EOF
SET PAGESIZE 0 FEEDBACK OFF
SELECT 'Size: ' || ROUND(space_limit/1024/1024/1024, 2) || 'GB, Used: ' ||
ROUND(space_used/1024/1024/1024, 2) || 'GB (' ||
ROUND((space_used/space_limit)*100, 2) || '%)'
FROM v\$recovery_file_dest;
EXIT;
EOF
# RMAN cleanup
echo ""
echo "Running RMAN cleanup..."
rman target / << EOF
# Crosscheck and delete expired files
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
# Delete obsolete backups
DELETE NOPROMPT OBSOLETE;
# Delete old archive logs based on retention
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-${RETENTION_DAYS}';
# Report remaining files
REPORT OBSOLETE;
EXIT;
EOF
# Check FRA usage after cleanup
echo ""
echo "FRA usage after cleanup:"
sqlplus -s / as sysdba << EOF
SET PAGESIZE 0 FEEDBACK OFF
SELECT 'Size: ' || ROUND(space_limit/1024/1024/1024, 2) || 'GB, Used: ' ||
ROUND(space_used/1024/1024/1024, 2) || 'GB (' ||
ROUND((space_used/space_limit)*100, 2) || '%)'
FROM v\$recovery_file_dest;
EXIT;
EOF
echo "FRA Cleanup completed: $(date)"
echo "========================================"
# Schedule this script in crontab:
# 0 2 * * * /path/to/automated_backup_cleanup.sh ORCL 7
-- FRA sizing calculation
WITH archive_stats AS (
SELECT
AVG(daily_gb) as avg_daily_archive_gb,
MAX(daily_gb) as max_daily_archive_gb
FROM (
SELECT
TO_CHAR(first_time, 'YYYY-MM-DD') as day,
SUM(blocks * block_size)/1024/1024/1024 as daily_gb
FROM v$archived_log
WHERE first_time > SYSDATE - 30
GROUP BY TO_CHAR(first_time, 'YYYY-MM-DD')
)
),
backup_stats AS (
SELECT
AVG(backup_size_gb) as avg_backup_gb,
MAX(backup_size_gb) as max_backup_gb
FROM (
SELECT
session_key,
SUM(output_bytes)/1024/1024/1024 as backup_size_gb
FROM v$rman_backup_job_details
WHERE start_time > SYSDATE - 30
AND status = 'COMPLETED'
GROUP BY session_key
)
)
SELECT
a.avg_daily_archive_gb,
a.max_daily_archive_gb,
b.avg_backup_gb,
b.max_backup_gb,
-- Recommended FRA size calculation
ROUND(
(a.max_daily_archive_gb * 7) + -- 7 days of max archive logs
(b.max_backup_gb * 2) + -- 2 full backup sets
5 -- 5GB overhead
, 0) as recommended_fra_size_gb
FROM archive_stats a, backup_stats b;
-- Create FRA monitoring table
CREATE TABLE fra_usage_log (
log_time TIMESTAMP DEFAULT SYSTIMESTAMP,
size_gb NUMBER,
used_gb NUMBER,
reclaimable_gb NUMBER,
pct_used NUMBER,
file_count NUMBER,
alert_sent CHAR(1) DEFAULT 'N'
);
-- Create FRA monitoring procedure
CREATE OR REPLACE PROCEDURE monitor_fra_usage AS
v_size_gb NUMBER;
v_used_gb NUMBER;
v_reclaimable_gb NUMBER;
v_pct_used NUMBER;
v_file_count NUMBER;
v_alert_threshold NUMBER := 85; -- Alert at 85%
BEGIN
-- Get FRA usage statistics
SELECT
ROUND(space_limit/1024/1024/1024, 2),
ROUND(space_used/1024/1024/1024, 2),
ROUND(space_reclaimable/1024/1024/1024, 2),
ROUND((space_used/space_limit)*100, 2),
number_of_files
INTO v_size_gb, v_used_gb, v_reclaimable_gb, v_pct_used, v_file_count
FROM v$recovery_file_dest;
-- Log usage statistics
INSERT INTO fra_usage_log (
size_gb, used_gb, reclaimable_gb, pct_used, file_count
) VALUES (
v_size_gb, v_used_gb, v_reclaimable_gb, v_pct_used, v_file_count
);
-- Alert if usage exceeds threshold
IF v_pct_used > v_alert_threshold THEN
DBMS_OUTPUT.PUT_LINE('ALERT: FRA usage at ' || v_pct_used || '%');
DBMS_OUTPUT.PUT_LINE('Used: ' || v_used_gb || 'GB of ' || v_size_gb || 'GB');
DBMS_OUTPUT.PUT_LINE('Reclaimable: ' || v_reclaimable_gb || 'GB');
-- Update alert flag
UPDATE fra_usage_log
SET alert_sent = 'Y'
WHERE log_time = (SELECT MAX(log_time) FROM fra_usage_log);
END IF;
COMMIT;
END;
/
-- Schedule FRA monitoring
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'MONITOR_FRA_JOB',
job_type => 'STORED_PROCEDURE',
job_action => 'monitor_fra_usage',
repeat_interval => 'FREQ=HOURLY',
enabled => TRUE
);
END;
/
-- Configure additional archive destinations for overflow
ALTER SYSTEM SET log_archive_dest_1 = 'LOCATION=USE_DB_RECOVERY_FILE_DEST' SCOPE = BOTH;
ALTER SYSTEM SET log_archive_dest_2 = 'LOCATION=/archive/overflow MANDATORY' SCOPE = BOTH;
ALTER SYSTEM SET log_archive_dest_3 = 'LOCATION=/archive/remote OPTIONAL' SCOPE = BOTH;
-- Enable destinations
ALTER SYSTEM SET log_archive_dest_state_1 = ENABLE SCOPE = BOTH;
ALTER SYSTEM SET log_archive_dest_state_2 = ENABLE SCOPE = BOTH;
ALTER SYSTEM SET log_archive_dest_state_3 = ENABLE SCOPE = BOTH;
-- Configure minimum successful destinations
ALTER SYSTEM SET log_archive_min_succeed_dest = 1 SCOPE = BOTH;
-- Enable archive log compression (12c+)
ALTER SYSTEM SET archive_lag_target = 900 SCOPE = BOTH; -- Force log switch every 15 min
ALTER SYSTEM SET log_archive_format = 'arch_%t_%s_%r.arc' SCOPE = SPFILE;
-- Create compressed archive destination
-- Note: Requires RMAN for compression, not direct ALTER SYSTEM
#!/bin/bash
# fra_monitor.sh - Continuous FRA monitoring
ORACLE_SID=${1:-ORCL}
ALERT_THRESHOLD=${2:-80}
EMAIL_ALERT=${3:-dba@company.com}
export ORACLE_SID
while true; do
FRA_PCT=$(sqlplus -s / as sysdba << EOF
SET PAGESIZE 0 FEEDBACK OFF
SELECT ROUND((space_used/space_limit)*100, 2)
FROM v\$recovery_file_dest;
EXIT;
EOF
)
if (( $(echo "$FRA_PCT > $ALERT_THRESHOLD" | bc -l) )); then
echo "$(date): ALERT - FRA usage at ${FRA_PCT}%"
# Send email alert
echo "FRA usage critical: ${FRA_PCT}%" | \
mail -s "Oracle FRA Alert - $ORACLE_SID" "$EMAIL_ALERT"
# Trigger automatic cleanup
/path/to/automated_backup_cleanup.sh "$ORACLE_SID" 3
else
echo "$(date): FRA usage OK: ${FRA_PCT}%"
fi
sleep 300 # Check every 5 minutes
done
-- Create capacity planning view
CREATE OR REPLACE VIEW fra_capacity_forecast AS
WITH daily_growth AS (
SELECT
TO_DATE(TO_CHAR(log_time, 'YYYY-MM-DD'), 'YYYY-MM-DD') as log_date,
MAX(used_gb) - MIN(used_gb) as daily_growth_gb
FROM fra_usage_log
WHERE log_time > SYSDATE - 30
GROUP BY TO_DATE(TO_CHAR(log_time, 'YYYY-MM-DD'), 'YYYY-MM-DD')
),
growth_stats AS (
SELECT
AVG(daily_growth_gb) as avg_daily_growth,
MAX(daily_growth_gb) as max_daily_growth,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY daily_growth_gb) as p95_daily_growth
FROM daily_growth
WHERE daily_growth_gb > 0
),
current_status AS (
SELECT
size_gb,
used_gb,
(size_gb - used_gb) as free_gb,
pct_used
FROM fra_usage_log
WHERE log_time = (SELECT MAX(log_time) FROM fra_usage_log)
)
SELECT
c.size_gb as current_size_gb,
c.used_gb as current_used_gb,
c.free_gb as current_free_gb,
c.pct_used as current_pct_used,
g.avg_daily_growth,
g.max_daily_growth,
g.p95_daily_growth,
ROUND(c.free_gb / g.avg_daily_growth, 1) as days_until_full_avg,
ROUND(c.free_gb / g.max_daily_growth, 1) as days_until_full_max,
ROUND(c.size_gb + (g.p95_daily_growth * 30), 0) as recommended_size_gb
FROM current_status c, growth_stats g;
-- Query capacity forecast
SELECT * FROM fra_capacity_forecast;
  • ORA-00257 - Archiver error (escalation from ORA-19815)
  • ORA-16038 - Log sequence cannot be archived
  • ORA-01652 - Unable to extend temp segment
  • ORA-19809 - Limit exceeded for recovery files (not documented yet)
  1. Check FRA status immediately

    SELECT ROUND((space_used/space_limit)*100,2) as pct_used FROM v$recovery_file_dest;
  2. Emergency space increase

    ALTER SYSTEM SET db_recovery_file_dest_size = 100G SCOPE = BOTH;
  3. Quick RMAN cleanup

    RMAN TARGET /
    DELETE NOPROMPT EXPIRED BACKUP;
    DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-1';
    EXIT;
  4. Monitor recovery

    SELECT * FROM v$recovery_area_usage ORDER BY percent_space_used DESC;
-- Check FRA usage
SELECT space_limit/1024/1024/1024 as size_gb,
space_used/1024/1024/1024 as used_gb,
ROUND((space_used/space_limit)*100,2) as pct_used
FROM v$recovery_file_dest;
-- Increase FRA size
ALTER SYSTEM SET db_recovery_file_dest_size = 100G SCOPE = BOTH;
-- RMAN emergency cleanup
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT OBSOLETE;
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-2';
-- Check what's consuming space
SELECT file_type, percent_space_used, number_of_files
FROM v$recovery_area_usage ORDER BY percent_space_used DESC;
emergency_fra_cleanup.sh
#!/bin/bash
ORACLE_SID=${1:-ORCL}
export ORACLE_SID
echo "Emergency FRA cleanup for $ORACLE_SID..."
# Increase FRA size temporarily
sqlplus / as sysdba << EOF
ALTER SYSTEM SET db_recovery_file_dest_size = 200G SCOPE = MEMORY;
EXIT;
EOF
# RMAN cleanup
rman target / << EOF
CROSSCHECK BACKUP;
DELETE NOPROMPT EXPIRED BACKUP;
DELETE NOPROMPT OBSOLETE;
DELETE NOPROMPT ARCHIVELOG UNTIL TIME 'SYSDATE-1';
EXIT;
EOF
echo "Emergency cleanup completed"