Chapter 65 · Exporting RDS To S3
Subchapter 65.1
references/export-rds-to-s3.mdMarkdown58 KBView on GitHub
This SOP guides you through exporting Amazon RDS database snapshots or Aurora cluster snapshots to Amazon S3 for analytics, backup archival, long-term storage, or data migration purposes. AWS provides a native snapshot export feature that converts database snapshots to Apache Parquet format in S3, making the data accessible for analytics tools like Amazon Athena, Amazon Redshift Spectrum, and AWS Glue. The SOP handles the complete workflow including snapshot identification or creation, IAM role setup with proper permissions, KMS key configuration for encryption, S3 bucket preparation, export task initiation, progress monitoring, and verification of exported data.
Prompt the user in a single message to provide all required parameters at once. Clearly list the required parameters and their descriptions, and include any optional parameters with their default values. Do not proceed until you have received and confirmed all required parameters. If any required parameter is missing or unclear, you MUST explicitly request the missing information before moving forward.
Only proceed to the steps below if you have all required information.
Check for required tools and warn the user if any are missing.
Constraints:
Verify the database exists and determine whether it’s RDS or Aurora.
Constraints:
aws rds describe-db-instances --db-instance-identifier ${database_identifier} --region ${region}aws rds describe-db-clusters --db-cluster-identifier ${database_identifier} --region ${region}Identify the snapshot to export based on user preferences.
Constraints:
You MUST handle three export type scenarios:
Scenario A: latest-snapshot (default)
aws rds describe-db-snapshots --db-instance-identifier ${database_identifier} --region ${region}aws rds describe-db-cluster-snapshots --db-cluster-identifier ${database_identifier} --region ${region}Scenario B: specific-snapshot
aws rds describe-db-snapshots --db-snapshot-identifier ${snapshot_identifier} --region ${region}aws rds describe-db-cluster-snapshots --db-cluster-snapshot-identifier ${snapshot_identifier} --region ${region}Scenario C: create-new-snapshot
You MUST generate a snapshot identifier: ${database_identifier}-export-${timestamp}
You MUST create a new manual snapshot:
aws rds create-db-snapshot --db-instance-identifier ${database_identifier} --db-snapshot-identifier ${snapshot_id} --tags Key=Purpose,Value=S3Export Key=CreatedBy,Value=export-rds-to-s3-script --region ${region}aws rds create-db-cluster-snapshot --db-cluster-identifier ${database_identifier} --db-cluster-snapshot-identifier ${snapshot_id} --tags Key=Purpose,Value=S3Export Key=CreatedBy,Value=export-rds-to-s3-script --region ${region}You MUST poll snapshot status until it becomes “available”:
You MUST inform user of snapshot creation progress:
Creating snapshot ${snapshot_id}...
Status: creating (0:30)
Status: creating (1:00)
Status: creating (1:30)
Status: available (2:15) ✓
Snapshot created successfully!You MUST handle snapshot creation failures by surfacing the AWS error code/message to the user and recommending actionable next steps
You MUST verify snapshot is encrypted if the source database is encrypted
You MUST save the selected snapshot identifier for the export operation
You MUST display snapshot details including:
Ensure the S3 bucket exists and is properly configured for RDS export.
Constraints:
aws s3api head-bucket --bucket ${s3_bucket_name}aws s3api get-bucket-location --bucket ${s3_bucket_name}aws s3api get-bucket-encryption --bucket ${s3_bucket_name}aws s3 ls s3://${s3_bucket_name}/${s3_prefix}aws s3api put-object --bucket ${s3_bucket_name} --key ${s3_prefix}Set up IAM role with permissions for RDS to write exported data to S3.
Constraints:
You MUST skip role creation if iam_role_arn was provided and verify it instead
You MUST check if provided IAM role exists: aws iam get-role --role-name ${role_name}
You MUST verify the role has correct trust policy for RDS export service with confused deputy protection:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "export.rds.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "${account_id}"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:rds:${region}:${account_id}:*"
}
}
}
]
}You MUST obtain the account ID for the trust policy condition: aws sts get-caller-identity --query Account --output text
You MUST create IAM role if not provided:
${database_identifier}-export-role or rds-s3-export-role${account_id} and ${region} substitutedaws iam create-role --role-name ${role_name} --assume-role-policy-document file://trust-policy.json --description "IAM role for RDS snapshot export to S3 for ${database_identifier}"You MUST create IAM policy with necessary S3 permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject*",
"s3:GetObject*",
"s3:DeleteObject*"
],
"Resource": "arn:aws:s3:::${s3_bucket_name}/${s3_prefix}*"
},
{
"Effect"
You MUST add KMS permissions if KMS key is specified:
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "arn:aws:kms:${region}:${account_id}:key/${kms_key_id}"
}You MUST create and attach the policy:
aws iam create-policy --policy-name ${policy_name} --policy-document file://export-policy.jsonaws iam attach-role-policy --role-name ${role_name} --policy-arn ${policy_arn}You MUST add tags to the IAM role:
aws iam tag-role --role-name ${role_name} --tags Key=Purpose,Value=RDSSnapshotExport Key=Database,Value=${database_identifier} Key=ManagedBy,Value=export-rds-to-s3-scriptYou MUST wait for IAM role propagation (10-15 seconds):
You MUST verify role ARN format is correct:
arn:aws:iam::${account_id}:role/${role_name}aws sts get-caller-identity --query Account --output textYou MUST present IAM configuration summary:
You MUST handle IAM creation errors:
Set up KMS encryption for exported data in S3 if required.
Constraints:
You MUST skip this step if no KMS key was specified and default S3 encryption is acceptable
You MUST verify the KMS key exists: aws kms describe-key --key-id ${kms_key_id} --region ${region}
You MUST check KMS key status is “Enabled”
You MUST verify the key is in the same region as the export operation
You MUST ensure the KMS key policy allows RDS export service to use it:
{
"Sid": "Allow RDS Export Service",
"Effect": "Allow",
"Principal": {
"Service": "export.rds.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "rds.${region}.amazonaws.com"
}
}
}You MUST check if snapshot is encrypted with different KMS key:
You MUST add KMS key permissions to the IAM role (handled in previous step)
You MUST verify IAM role can use the KMS key:
You MUST inform user of encryption details:
You MUST warn about performance impact if re-encryption is required:
You MUST handle KMS errors:
Identify specific tables for export if selective export is requested.
Constraints:
export_only_tables is not specified (exports entire database)schema.table or just table (for databases without explicit schemas)Create a unique identifier for the export task.
Constraints:
export_task_identifier if specified${database_identifier}-export-${timestamp}aws rds describe-export-tasks --export-task-identifier ${export_task_id} --region ${region}Start the export process to transfer snapshot data to S3.
Constraints:
Before executing the export command, you MUST confirm with the user that Parquet output meets their needs and reiterate its key benefits (columnar storage, compression, analytics tool compatibility); offer alternative approaches if Parquet is not acceptable
You MUST construct the export task command with all required parameters:
aws rds start-export-task \
--export-task-identifier ${export_task_id} \
--source-arn ${snapshot_arn} \
--s3-bucket-name ${s3_bucket_name} \
--s3-prefix ${s3_prefix} \
--iam-role-arn ${iam_role_arn} \
--kms-key-id ${kms_key_id} \
--export-only ${export_only_tables} \
--region ${region}You MUST construct correct snapshot ARN:
arn:aws:rds:${region}:${account_id}:snapshot:${snapshot_id}arn:aws:rds:${region}:${account_id}:cluster-snapshot:${snapshot_id}aws sts get-caller-identity --query Account --output textYou MUST include optional parameters only if specified:
--kms-key-id only if KMS encryption is configured--export-only only if selective table export is requestedYou MUST handle export task creation errors:
You MUST capture export task details from response:
You MUST display export task initiation confirmation:
✓ Export task started successfully!
Export Task ID: production-mysql-export-20251014-153045
Snapshot: production-mysql-snapshot-2025-10-14
Destination: s3://my-rds-exports/rds-exports/
Status: starting
Started: 2025-10-14 15:30:45 UTCYou MUST inform user of expected export duration:
You MUST save export task identifier for progress monitoring
Track the export operation until completion.
Constraints:
You MUST poll export task status regularly:
aws rds describe-export-tasks --export-task-identifier ${export_task_id} --region ${region}You MUST extract and display key information from each status check:
You MUST display progress updates to user:
Exporting snapshot to S3...
Status: in_progress (5%, 2.5 GB exported, 0:15 elapsed)
Status: in_progress (15%, 7.5 GB exported, 0:45 elapsed)
Status: in_progress (30%, 15 GB exported, 1:30 elapsed)
Status: in_progress (50%, 25 GB exported, 2:30 elapsed)
Status: in_progress (75%, 37.5 GB exported, 3:45 elapsed)
Status: in_progress (90%, 45 GB exported, 4:30 elapsed)
Status: complete (100%, 50 GB exported, 5:00 elapsed) ✓You MUST handle different status outcomes:
You MUST check for warnings during export:
You MUST implement timeout handling:
You MUST handle export failures gracefully:
You MUST inform user they can safely close terminal:
You MUST calculate export metrics upon completion:
Confirm the export completed successfully and data is accessible in S3.
Constraints:
aws s3 ls s3://${s3_bucket_name}/${s3_prefix}${export_task_id}/ --recursiveCheck for expected folders and files
Typical structure:
s3://bucket/prefix/export-task-id/
├── schema1/
│ ├── table1/
│ │ ├── data1.parquet
│ │ ├── data2.parquet
│ │ └── ...
│ └── table2/
│ └── data1.parquet
└── schema2/
└── table3/
└── data1.parquetEach table has one or more Parquet files
Large tables are split across multiple Parquet files
aws s3api head-object --bucket ${s3_bucket_name} --key ${sample_file_key}s3://${s3_bucket_name}/${s3_prefix}${export_task_id}/Guide user on how to query and use the exported data.
Constraints:
You MUST provide multiple options for accessing exported data:
Option 1: Amazon Athena
Create external table in Athena to query Parquet data
Provide sample CREATE EXTERNAL TABLE DDL:
CREATE EXTERNAL TABLE IF NOT EXISTS database_name.table_name (
column1 data_type,
column2 data_type,
column3 data_type
)
STORED AS PARQUET
LOCATION 's3://${s3_bucket_name}/${s3_prefix}${export_task_id}/schema/table/';Provide sample SELECT query:
SELECT * FROM database_name.table_name LIMIT 10;Explain need to create Athena database first
Mention Athena query costs ($5 per TB scanned)
Option 2: AWS Glue
Create Glue crawler to automatically discover schema
Provide crawler creation command:
aws glue create-crawler \
--name ${database_identifier}-export-crawler \
--role ${glue_service_role} \
--database ${glue_database} \
--targets "S3Targets=[{Path=s3://${s3_bucket_name}/${s3_prefix}${export_task_id}/}]" \
--region ${region}Explain how to run crawler and view Data Catalog
Mention Glue crawling costs
Option 3: Amazon Redshift Spectrum
Create external schema in Redshift pointing to S3 data
Provide sample DDL:
CREATE EXTERNAL SCHEMA spectrum_schema
FROM DATA CATALOG
DATABASE 'glue_database'
IAM_ROLE 'arn:aws:iam::account-id:role/redshift-spectrum-role'
REGION '${region}';
SELECT * FROM spectrum_schema.table_name LIMIT 10;Explain querying from Redshift cluster
Option 4: Direct Parquet File Access
Download Parquet files locally:
aws s3 cp s3://${s3_bucket_name}/${s3_prefix}${export_task_id}/ ./local-folder/ --recursiveUse Python with pandas/pyarrow to read:
import pandas as pd
import pyarrow.parquet as pq
# Read Parquet file
table = pq.read_table('data.parquet')
df = table.to_pandas()
print(df.head())You MUST explain Parquet format benefits when confirming the export approach and again here if the user needs a refresher:
You MUST provide schema discovery guidance:
pq.read_schema('file.parquet')You MUST warn about data consistency:
You MUST provide cost estimates for common access patterns:
Create comprehensive documentation of the export operation.
Constraints:
You MUST create a detailed export report containing:
You MUST format the report in clear, readable markdown format
You MUST include specific commands for all recommendations
You MUST provide AWS Console URLs for easy access:
You MUST save report to file: rds-export-report-${export_task_id}.md
You MUST present the complete report to the user
You MUST offer to save the report to a local file for reference
Advise on managing exported data and optimizing costs.
Constraints:
You MUST provide instructions for deleting exported data when no longer needed:
# Delete exported data from S3
aws s3 rm s3://${s3_bucket_name}/${s3_prefix}${export_task_id}/ --recursive
# Delete the snapshot if it was created for export only
aws rds delete-db-snapshot --db-snapshot-identifier ${snapshot_id} --region ${region}
# Or for Aurora cluster snapshot:
aws rds delete-db-cluster-snapshot --db-cluster-snapshot-identifier ${snapshot_id} --region ${region}You MUST recommend S3 lifecycle policies for cost optimization:
Transition to S3 Intelligent-Tiering after 30 days
Or transition to S3 Glacier after 90 days for archival
Delete after retention period expires
Example lifecycle policy:
{
"Rules": [
{
"Id": "Archive RDS Exports",
"Status": "Enabled",
"Filter": {
"Prefix": "${s3_prefix}"
},
"Transitions": [
{
"Days": 30,
"StorageClass": "INTELLIGENT_TIERING"
Apply policy: aws s3api put-bucket-lifecycle-configuration --bucket ${s3_bucket_name} --lifecycle-configuration file://lifecycle.json
You MUST recommend monitoring and alerting:
CloudWatch alarm for failed exports
S3 storage metrics to track growth
Cost alerts for unexpected charges
Example alarm creation:
aws cloudwatch put-metric-alarm \
--alarm-name rds-export-failures \
--alarm-description "Alert on RDS export task failures" \
--metric-name ExportTaskFailures \
--namespace AWS/RDS \
--statistic Sum \
--period 300 \
--threshold 1 \
--comparison-operator GreaterThanThresholdYou MUST suggest automation for recurring exports:
AWS Lambda function triggered by EventBridge (CloudWatch Events) schedule
Step Functions workflow for complex export logic
Example Lambda trigger setup:
# Create EventBridge rule to run daily
aws events put-rule \
--name daily-rds-export \
--schedule-expression "cron(0 2 * * ? *)" \
--state ENABLED
# Add Lambda function as target
aws events put-targets \
--rule daily-rds-export \
--targets "Id=1,Arn=${lambda_function_arn}"You MUST provide cost optimization tips:
You MUST recommend data retention policies:
database_identifier: production-mysql
region: us-east-1
s3_bucket_name: analytics-data-lake
s3_prefix: rds-exports/mysql/
export_type: latest-snapshot# RDS Snapshot Export to S3 - Summary Report
**Export Task ID:** production-mysql-export-20251014-153045
**Status:** ✓ Completed Successfully
**Generated:** 2025-10-14 20:45:30 UTC
---
## Export Overview
Successfully exported RDS MySQL snapshot to S3 for analytics and backup purposes.
- **Database:** production-mysql (MySQL 8.0.35)
- **Snapshot:** production-mysql-automated-2025-10-14-12-30
- **Export Status:** Complete
- **Duration:** 5 hours 15 minutes
- **Data Exported:** 245 GB → 92 GB Parquet (62% compression)
---
## Source Configuration
### Database Details
- **DB Instance:** production-mysql
- **Engine:** MySQL 8.0.35
- **Instance Class:** db.r5.2xlarge
- **Region:** us-east-1
- **Multi-AZ:** Yes
- **Storage:** 500 GB (gp3)
- **Encrypted:** Yes (KMS key: arn:aws:kms:us-east-1:123456789012:key/abcd1234-...)
### Snapshot Details
- **Snapshot ID:** production-mysql-automated-2025-10-14-12-30
- **Type:** Automated backup
- **Created:** 2025-10-14 12:30:00 UTC
- **Size:** 245 GB
- **Status:** Available
- **Encrypted:** Yes (same KMS key as instance)
---
## Destination Configuration
### S3 Export Location
- **Bucket:** analytics-data-lake
- **Region:** us-east-1 (same as database)
- **Prefix:** rds-exports/mysql/
- **Full Path:** s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/
- **Console URL:** https://s3.console.aws.amazon.com/s3/buckets/analytics-data-lake?prefix=rds-exports/mysql/production-mysql-export-20251014-153045/
### Exported Data
- **Format:** Apache Parquet
- **Compression:** Snappy (default)
- **Total Size:** 92 GB
- **Files:** 1,247 Parquet files
- **Tables:** 87 tables exported
- **Encryption:** SSE-KMS (KMS key: arn:aws:kms:us-east-1:123456789012:key/abcd1234-...)
### Data Structures3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/ ├── appdb/ │ ├── users/ │ │ ├── 1.parquet │ │ ├── 2.parquet │ │ └── ... (15 files, 8.2 GB) │ ├── orders/ │ │ ├── 1.parquet │ │ └── ... (42 files, 18.5 GB) │ ├── products/ │ │ └── 1.parquet (2.1 GB) │ └── ... (87 tables total) └── ...
---
## IAM and Security Configuration
### IAM Role
- **Role ARN:** arn:aws:iam::123456789012:role/production-mysql-export-role
- **Trust Policy:** Allows export.rds.amazonaws.com
- **Created:** 2025-10-14 15:25:00 UTC
### IAM Permissions
- **S3 Access:** PutObject, GetObject, DeleteObject on s3://analytics-data-lake/rds-exports/mysql/*
- **S3 List:** ListBucket on analytics-data-lake
- **KMS Access:** Decrypt (snapshot key), GenerateDataKey (export key)
### Encryption
- **Snapshot Encryption:** Yes (KMS key: abcd1234-5678-90ab-cdef-1234567890ab)
- **Export Encryption:** Yes (same KMS key)
- **Re-encryption:** No (same key used)
- **S3 Bucket Encryption:** SSE-KMS enabled
---
## Export Metrics
### Performance
- **Total Data Exported:** 92 GB (Parquet format)
- **Original Snapshot Size:** 245 GB
- **Compression Ratio:** 62% reduction
- **Export Duration:** 5 hours 15 minutes (315 minutes)
- **Average Speed:** 17.5 GB/hour
- **Start Time:** 2025-10-14 15:30:00 UTC
- **End Time:** 2025-10-14 20:45:00 UTC
### Data Details
- **Tables Exported:** 87 (all tables)
- **Parquet Files Created:** 1,247 files
- **Largest Table:** orders (18.5 GB, 42 Parquet files)
- **Smallest Table:** config (12 MB, 1 Parquet file)
- **Warnings:** None
---
## Accessing Exported Data
### Option 1: Query with Amazon Athena
1. **Create Athena Database:**
```sql
CREATE DATABASE IF NOT EXISTS production_mysql_export;Create External Table (Example for ‘users’ table):
CREATE EXTERNAL TABLE IF NOT EXISTS production_mysql_export.users (
id INT,
username STRING,
email STRING,
created_at TIMESTAMP,
updated_at TIMESTAMP
)
STORED AS PARQUET
LOCATION 's3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/appdb/users/';Query Data:
SELECT COUNT(*) as total_users FROM production_mysql_export.users;
SELECT * FROM production_mysql_export.users WHERE created_at > '2025-01-01' LIMIT 100;Cost: ~$5 per TB scanned (92 GB = $0.46 per full scan)
Create Glue Database:
aws glue create-database \
--database-input "Name=production_mysql_export,Description=Exported from RDS" \
--region us-east-1Create Glue Crawler:
aws glue create-crawler \
--name production-mysql-export-crawler \
--role arn:aws:iam::123456789012:role/AWSGlueServiceRole \
--database-targets DatabaseTargets=[{DatabaseName=production_mysql_export,Path=s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/}] \
--region us-east-1Run Crawler:
aws glue start-crawler --name production-mysql-export-crawler --region us-east-1Query via Athena:
Create External Schema in Redshift:
CREATE EXTERNAL SCHEMA mysql_export
FROM DATA CATALOG
DATABASE 'production_mysql_export'
IAM_ROLE 'arn:aws:iam::123456789012:role/RedshiftSpectrumRole'
REGION 'us-east-1';Query from Redshift:
SELECT * FROM mysql_export.users LIMIT 100;
-- Join with Redshift tables
SELECT u.username, o.order_total
FROM mysql_export.users u
JOIN local_schema.orders o ON u.id = o.user_id;Download with AWS CLI:
# Download all data
aws s3 cp s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/ ./rds-export/ --recursive
# Download specific table
aws s3 cp s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/appdb/users/ ./users-data/ --recursiveProcess with Python:
import pandas as pd
import pyarrow.parquet as pq
import boto3
# Option A: Read from local file
df = pd.read_parquet('users-data/1.parquet')
print(df.head())
# Option B: Read directly from S3
s3 = boto3.client('s3')
obj = s3.get_object(Bucket='analytics-data-lake',
Key='rds-exports/mysql/production-mysql-export-20251014-153045/appdb/users/1.parquet')
table = pq.read_table(obj['Body'])
df = table.to_pandas()
# Option C: Read all Parquet files in a directory
df = pd.read_parquet('s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/appdb/users/')Process with Apache Spark:
val df = spark.read.parquet("s3a://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/appdb/users/")
df.show()
df.printSchema()
df.count()Estimated Monthly Cost with Optimization: $0.37/month (Glacier after 90 days)
# Delete all exported data from S3
aws s3 rm s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/ --recursive
# Verify deletion
aws s3 ls s3://analytics-data-lake/rds-exports/mysql/production-mysql-export-20251014-153045/# For automated snapshots (not recommended - managed by RDS)
# For manual snapshots created for export:
aws rds delete-db-snapshot \
--db-snapshot-identifier production-mysql-manual-export-snapshot \
--region us-east-1# Detach policies first
aws iam detach-role-policy \
--role-name production-mysql-export-role \
--policy-arn arn:aws:iam::123456789012:policy/ProductionMySQLExportPolicy
# Delete policy
aws iam delete-policy \
--policy-arn arn:aws:iam::123456789012:policy/ProductionMySQLExportPolicy
# Delete role
aws iam delete-role --role-name production-mysql-export-roleConfigure S3 Lifecycle Policy (Save 40-85% on storage costs)
# Apply lifecycle policy to automatically transition to cheaper storage
aws s3api put-bucket-lifecycle-configuration \
--bucket analytics-data-lake \
--lifecycle-configuration file://lifecycle-policy.jsonSet Up CloudWatch Alarms (Monitor export failures)
aws cloudwatch put-metric-alarm \
--alarm-name rds-export-failures \
--alarm-description "Alert on RDS export task failures" \
--metric-name ExportTaskFailures \
--namespace AWS/RDS \
--statistic Sum \
--period 300 \
--threshold 1 \
--comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:us-east-1:123456789012:alertsEnable S3 Versioning (Protect against accidental deletion)
aws s3api put-bucket-versioning \
--bucket analytics-data-lake \
--versioning-configuration Status=EnabledTag S3 Objects (Organize and track exports)
aws s3api put-object-tagging \
--bucket analytics-data-lake \
--key rds-exports/mysql/production-mysql-export-20251014-153045/ \
--tagging 'TagSet=[{Key=Database,Value=production-mysql},{Key=ExportDate,Value=2025-10-14},{Key=RetentionDays,Value=90}]'Automate Recurring Exports (Daily/Weekly snapshots)
Implement Data Retention Policy
Set Up Data Catalog and Governance
Optimize for Analytics Workloads
Monitor and Optimize Costs
amazon-rds or amazon-athenaSuccessfully exported 245 GB MySQL database snapshot to S3 in Parquet format (92 GB compressed). Data is now available for analytics via Amazon Athena, AWS Glue, Amazon Redshift Spectrum, or direct file access. Export completed in 5 hours 15 minutes with no errors or warnings, and status updates were delivered on the agreed asynchronous schedule.
Next Steps:
Export Details:
Report generated by export-rds-to-s3-script on 2025-10-14 20:45:30 UTC
## Troubleshooting
### Database Not Found
**Symptoms:** DB instance or cluster identifier not found
**Solutions:**
- Verify database identifier spelling and case (case-sensitive)
- Check you're in the correct AWS region
- Use `aws rds describe-db-instances --region ${region}` to list all instances
- For Aurora, use `aws rds describe-db-clusters --region ${region}`
- Verify you have permissions to describe RDS resources
### Export Not Supported for Database Engine
**Symptoms:** Error indicating database engine doesn't support export
**Solutions:**
- Snapshot export is supported for: MySQL, PostgreSQL, MariaDB, Aurora MySQL, Aurora PostgreSQL
- NOT supported for: Oracle, SQL Server
- For unsupported engines, consider alternative backup methods:
- Native database backup tools (mysqldump, pg_dump)
- AWS Database Migration Service (DMS) for data replication
- Third-party backup solutions
- Check engine version meets minimum requirements
### Snapshot Not Available
**Symptoms:** Snapshot status is not "available" or snapshot doesn't exist
**Solutions:**
- Wait for automated snapshots to complete (taken during backup window)
- Check snapshot creation is not disabled on DB instance
- Verify snapshot retention period is not set to 0
- For Aurora, cluster snapshots may be in different namespace than instance snapshots
- List all snapshots: `aws rds describe-db-snapshots --db-instance-identifier ${db_id}`
- Create manual snapshot and wait for "available" status
### IAM Role Permission Errors
**Symptoms:** Export fails with access denied or insufficient permissions
**Solutions:**
- Verify IAM role has trust policy allowing export.rds.amazonaws.com
- Check S3 bucket policy allows RDS export service principal
- Ensure IAM role has PutObject permissions on S3 bucket and prefix
- Verify KMS key policy allows export service to use key
- Wait 10-15 seconds after creating IAM role (eventual consistency)
- Test IAM role with `aws sts assume-role` to verify trust policy
- Check for typos in ARNs (role ARN, bucket ARN, KMS key ARN)
### S3 Bucket Access Denied
**Symptoms:** Export fails with S3 access denied errors
**Solutions:**
- Verify S3 bucket exists and is accessible
- Check bucket is not in different AWS account (cross-account requires additional configuration)
- Ensure bucket policy allows RDS export service:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "export.rds.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::bucket-name/prefix/*"
}
]
}aws s3 cp testfile.txt s3://bucket-name/prefix/Symptoms: Export fails with KMS key not accessible or decrypt errors
Solutions:
aws kms describe-key --key-id ${key_id} to check key statusSymptoms: Export task remains in “starting” status for extended time
Solutions:
aws rds cancel-export-task --export-task-identifier ${task_id}Symptoms: Export fails after starting successfully
Solutions:
aws rds describe-export-tasks --export-task-identifier ${task_id}Symptoms: Expected tables are not present in S3 export
Solutions:
Symptoms: Cannot open or query Parquet files
Solutions:
Symptoms: Unexpected charges for export operation or storage
Solutions:
Symptoms: Cannot query exported Parquet files with Athena
Solutions:
Symptoms: Export taking much longer than expected
Solutions:
Symptoms: Export task remains visible even after completion
Solutions:
Export tasks are permanent records and cannot be deleted
They remain visible in AWS console and API responses
Use descriptive naming to identify old exports
Filter by date when listing export tasks
Export task metadata is free (no storage cost)
Focus on deleting exported S3 data instead:
aws s3 rm s3://bucket/prefix/export-task-id/ --recursiveSymptoms: Export fails or incurs unexpected costs with cross-region setup
Solutions:
This file
Use Apache Spark:
val df = spark.read.parquet("s3a://${s3_bucket_name}/${s3_prefix}${export_task_id}/schema/table/")
df.show()