[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6P0GRC7TJ8DWSYSCFH68PDF":3,"skill-same:01M6P0GRC7TJ8DWSYSCFH68PDF":79},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":25,"publishedAt":46,"linkOnly":47,"markdownContent":48,"markdownBody":49,"frontMatter":50,"refName":36,"commitSha":60,"skillDirectory":61,"forksCount":13,"repositoryHtmlUrl":62,"repositoryHomepageUrl":6,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":64,"install":65,"resources":78},"01M6P0GRC7TJ8DWSYSCFH68PDF","database-backups",null,"Implement database backup strategies. Configure automated backups, retention, and recovery testing. Use when designing backup and recovery procedures.","duc-duy-1612\u002FOnline-Delivery-Systems-Web","duc-duy-1612","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F192231384?v=4","01M6NSDKQQDKVTHZ8DZMZ1VYY6","01M6NSDKW8DDVTQHBT1HBDDJPT",0,"MIT","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fdatabase-backups\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口",[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45],"database backups","database","community","relevant","retention","scripts","critical","os","platform","strategies","main","testing","agent-skills","only","use","configure","access","devops-security","license","security","2026-11-10 10:12:30",false,"---\nname: database-backups\ndescription: Implement database backup strategies. Configure automated backups, retention,\n  and recovery testing. Use when designing backup and recovery procedures.\ncategory: devops\nrisk: critical\nsource: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\nsource_repo: BagelHole\u002FDevOps-Security-Agent-Skills\nsource_type: community\ndate_added: '2026-09-20'\nlicense: MIT\nlicense_source: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE\ncompatibility: Requires the relevant OS\u002Fplatform tooling and privileged access where\n  noted. Docs-only; helper scripts and templates not bundled.\nmetadata:\n  author: devops-skills\n  version: '1.0'\n---\n\n# Database Backups\n\nImplement comprehensive, automated database backup strategies with tested recovery procedures.\n\n## When to Use\n\n- You are deploying a new database and need a backup plan from day one.\n- You need to automate nightly or hourly backups for PostgreSQL, MySQL, or MongoDB.\n- You want to ship backups to S3-compatible object storage with retention policies.\n- You are building or verifying disaster recovery runbooks.\n\n## Prerequisites\n\n- Database client tools installed (`pg_dump`, `mysqldump`, `mongodump`).\n- AWS CLI or `restic` for remote storage.\n- `cron` or systemd timers for scheduling.\n- An S3 bucket (or S3-compatible endpoint) for offsite backups.\n\n## Backup Types\n\n| Type | Description | Frequency | Use Case |\n|---|---|---|---|\n| Full | Complete database copy | Weekly | Baseline for restores |\n| Incremental | Changes since last backup | Daily | Reduce storage and time |\n| Transaction log \u002F WAL | Continuous log shipping | Continuous | Point-in-time recovery (PITR) |\n| Snapshot | Storage-level snapshot (EBS, ZFS) | Daily | Fast full restores |\n\n## PostgreSQL Backups\n\n### Logical Backup with pg_dump\n\n```bash\n#!\u002Fbin\u002Fbash\n# pg_backup.sh — PostgreSQL logical backup\nset -euo pipefail\n\nDB_NAME=\"mydb\"\nDB_USER=\"backup_user\"\nDB_HOST=\"localhost\"\nBACKUP_DIR=\"\u002Fbackups\u002Fpostgres\"\nDATE=$(date +%Y%m%d_%H%M%S)\nFILENAME=\"${BACKUP_DIR}\u002F${DB_NAME}_${DATE}.dump\"\n\nmkdir -p \"$BACKUP_DIR\"\n\n# Custom compressed format (recommended for selective restore)\npg_dump -h \"$DB_HOST\" -U \"$DB_USER\" -Fc -Z6 \"$DB_NAME\" > \"$FILENAME\"\n\necho \"[$(date)] PostgreSQL backup complete: $FILENAME ($(du -h \"$FILENAME\" | cut -f1))\"\n```\n\n### Physical Backup with pg_basebackup\n\n```bash\n#!\u002Fbin\u002Fbash\n# pg_basebackup.sh — PostgreSQL physical backup for PITR\nset -euo pipefail\n\nBACKUP_DIR=\"\u002Fbackups\u002Fpostgres\u002Fbase_$(date +%Y%m%d)\"\nmkdir -p \"$BACKUP_DIR\"\n\npg_basebackup \\\n  -h localhost \\\n  -U replicator \\\n  -D \"$BACKUP_DIR\" \\\n  --wal-method=stream \\\n  --checkpoint=fast \\\n  --progress \\\n  --verbose\n\necho \"[$(date)] Base backup complete: $BACKUP_DIR\"\n```\n\n### PostgreSQL Restore\n\n```bash\n# Restore from custom-format dump\npg_restore -h localhost -U myapp -d mydb --clean --if-exists \u002Fbackups\u002Fpostgres\u002Fmydb_20250115_020000.dump\n\n# Restore a single table\npg_restore -h localhost -U myapp -d mydb -t orders \u002Fbackups\u002Fpostgres\u002Fmydb_20250115_020000.dump\n\n# Restore from plain SQL\npsql -h localhost -U myapp -d mydb \u003C \u002Fbackups\u002Fpostgres\u002Fmydb_20250115.sql\n```\n\n## MySQL Backups\n\n### Logical Backup with mysqldump\n\n```bash\n#!\u002Fbin\u002Fbash\n# mysql_backup.sh — MySQL logical backup\nset -euo pipefail\n\nDB_NAME=\"mydb\"\nDB_USER=\"backup_user\"\nDB_PASS=\"${MYSQL_BACKUP_PASSWORD}\"\nBACKUP_DIR=\"\u002Fbackups\u002Fmysql\"\nDATE=$(date +%Y%m%d_%H%M%S)\nFILENAME=\"${BACKUP_DIR}\u002F${DB_NAME}_${DATE}.sql.gz\"\n\nmkdir -p \"$BACKUP_DIR\"\n\nmysqldump -u \"$DB_USER\" -p\"$DB_PASS\" \\\n  --single-transaction \\\n  --routines \\\n  --triggers \\\n  --events \\\n  \"$DB_NAME\" | gzip > \"$FILENAME\"\n\necho \"[$(date)] MySQL backup complete: $FILENAME ($(du -h \"$FILENAME\" | cut -f1))\"\n```\n\n### Physical Backup with Percona XtraBackup\n\n```bash\n#!\u002Fbin\u002Fbash\n# xtrabackup.sh — MySQL physical backup\nset -euo pipefail\n\nBACKUP_DIR=\"\u002Fbackups\u002Fmysql\u002Ffull_$(date +%Y%m%d)\"\n\nxtrabackup --backup \\\n  --user=backup_user \\\n  --password \"$MYSQL_BACKUP_PASSWORD\" # from your vault; never hardcode \\\n  --target-dir=\"$BACKUP_DIR\"\n\nxtrabackup --prepare --target-dir=\"$BACKUP_DIR\"\n\necho \"[$(date)] XtraBackup complete: $BACKUP_DIR\"\n```\n\n### MySQL Restore\n\n```bash\n# Restore from compressed mysqldump\ngunzip \u003C \u002Fbackups\u002Fmysql\u002Fmydb_20250115_020000.sql.gz | mysql -u root -p mydb\n\n# Restore from XtraBackup\nsudo systemctl stop mysql\nls \u002Fvar\u002Flib\u002Fmysql\u002F*  # verify this is the correct data dir first\nsudo find \u002Fvar\u002Flib\u002Fmysql -mindepth 1 -delete  # empty the data dir; snapshots must exist (see Limitations)\nxtrabackup --move-back --target-dir=\u002Fbackups\u002Fmysql\u002Ffull_20250115\nsudo chown -R mysql:mysql \u002Fvar\u002Flib\u002Fmysql\nsudo systemctl start mysql\n```\n\n## MongoDB Backups\n\n### Logical Backup with mongodump\n\n```bash\n#!\u002Fbin\u002Fbash\n# mongo_backup.sh — MongoDB backup\nset -euo pipefail\n\nMONGO_URI=\"mongodb:\u002F\u002Fbackup_user:${MONGO_BACKUP_PASSWORD}@localhost:27017\"\nBACKUP_DIR=\"\u002Fbackups\u002Fmongodb\"\nDATE=$(date +%Y%m%d_%H%M%S)\nTARGET=\"${BACKUP_DIR}\u002F${DATE}\"\n\nmkdir -p \"$BACKUP_DIR\"\n\n# Full backup with compression\nmongodump --uri=\"$MONGO_URI\" --gzip --out=\"$TARGET\"\n\necho \"[$(date)] MongoDB backup complete: $TARGET\"\n```\n\n### MongoDB Restore\n\n```bash\n# Restore all databases\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002F\n\n# Restore a single database\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop --db mydb \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002Fmydb\u002F\n\n# Restore a single collection\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop --db mydb --collection users \\\n  \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002Fmydb\u002Fusers.bson.gz\n```\n\n## Upload to S3\n\n```bash\n#!\u002Fbin\u002Fbash\n# s3_upload.sh — Upload backups to S3\nset -euo pipefail\n\nS3_BUCKET=\"s3:\u002F\u002Fmy-backups\"\nBACKUP_DIR=\"\u002Fbackups\"\nDATE=$(date +%Y%m%d)\n\n# Upload PostgreSQL backup\naws s3 cp \"${BACKUP_DIR}\u002Fpostgres\u002F\" \"${S3_BUCKET}\u002Fpostgres\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\n# Upload MySQL backup\naws s3 cp \"${BACKUP_DIR}\u002Fmysql\u002F\" \"${S3_BUCKET}\u002Fmysql\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\n# Upload MongoDB backup\naws s3 cp \"${BACKUP_DIR}\u002Fmongodb\u002F\" \"${S3_BUCKET}\u002Fmongodb\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\necho \"[$(date)] S3 upload complete for ${DATE}\"\n```\n\n### S3 Lifecycle Policy for Retention\n\n```json\n{\n  \"Rules\": [\n    {\n      \"ID\": \"BackupRetention\",\n      \"Status\": \"Enabled\",\n      \"Filter\": { \"Prefix\": \"\" },\n      \"Transitions\": [\n        { \"Days\": 30, \"StorageClass\": \"GLACIER\" }\n      ],\n      \"Expiration\": { \"Days\": 365 }\n    }\n  ]\n}\n```\n\n```bash\naws s3api put-bucket-lifecycle-configuration \\\n  --bucket my-backups \\\n  --lifecycle-configuration file:\u002F\u002Flifecycle.json\n```\n\n## Restic Backup (Encrypted, Deduplicated)\n\n```bash\n# Initialize a restic repository on S3\nexport AWS_ACCESS_KEY_ID=\"AKIA...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport RESTIC_PASSWORD=\"...\" # set a strong restic password via your vault\nexport RESTIC_REPOSITORY=\"s3:s3.amazonaws.com\u002Fmy-backups-restic\"\n\nrestic init\n\n# Backup the local backup directory\nrestic backup \u002Fbackups\u002Fpostgres \u002Fbackups\u002Fmysql \u002Fbackups\u002Fmongodb\n\n# List snapshots\nrestic snapshots\n\n# Prune old snapshots — keep 7 daily, 4 weekly, 6 monthly\nrestic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune\n\n# Restore a snapshot\nrestic restore latest --target \u002Frestore\u002F\n```\n\n## Cron Schedules\n\n```bash\n# \u002Fetc\u002Fcron.d\u002Fdb-backups\n\n# PostgreSQL: nightly at 02:00\n0 2 * * * backup \u002Fopt\u002Fscripts\u002Fpg_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-pg.log 2>&1\n\n# MySQL: nightly at 02:30\n30 2 * * * backup \u002Fopt\u002Fscripts\u002Fmysql_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-mysql.log 2>&1\n\n# MongoDB: nightly at 03:00\n0 3 * * * backup \u002Fopt\u002Fscripts\u002Fmongo_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-mongo.log 2>&1\n\n# Upload to S3: daily at 04:00\n0 4 * * * backup \u002Fopt\u002Fscripts\u002Fs3_upload.sh >> \u002Fvar\u002Flog\u002Fbackup-s3.log 2>&1\n\n# Local cleanup: keep 7 days of local backups\n0 5 * * * backup find \u002Fbackups -type f -mtime +7 -delete >> \u002Fvar\u002Flog\u002Fbackup-cleanup.log 2>&1\n\n# Restic prune: weekly on Sunday at 06:00\n0 6 * * 0 backup \u002Fopt\u002Fscripts\u002Frestic_prune.sh >> \u002Fvar\u002Flog\u002Fbackup-restic.log 2>&1\n```\n\n## Automated Recovery Testing\n\n```bash\n#!\u002Fbin\u002Fbash\n# verify_backup.sh — weekly restore test\nset -euo pipefail\n\nBACKUP_FILE=$(ls -t \u002Fbackups\u002Fpostgres\u002Fmydb_*.dump | head -1)\n\necho \"[$(date)] Starting backup verification with $BACKUP_FILE\"\n\n# Spin up a temporary PostgreSQL container\ndocker run -d --name pg-restore-test \\\n  -e POSTGRES_USER=testuser \\\n  -e POSTGRES_PASSWORD=testpass \\\n  -e POSTGRES_DB=testdb \\\n  postgres:16-alpine\n\n# Wait for container to be ready\nsleep 5\nuntil docker exec pg-restore-test pg_isready -U testuser; do\n  sleep 2\ndone\n\n# Copy backup into container and restore\ndocker cp \"$BACKUP_FILE\" pg-restore-test:\u002Ftmp\u002Fbackup.dump\ndocker exec pg-restore-test pg_restore -U testuser -d testdb --clean --if-exists \u002Ftmp\u002Fbackup.dump\n\n# Run verification queries\nUSERS_COUNT=$(docker exec pg-restore-test psql -U testuser -d testdb -tAc \"SELECT COUNT(*) FROM users;\")\nORDERS_COUNT=$(docker exec pg-restore-test psql -U testuser -d testdb -tAc \"SELECT COUNT(*) FROM orders;\")\n\necho \"[$(date)] Verification: users=$USERS_COUNT, orders=$ORDERS_COUNT\"\n\n# Cleanup\ndocker rm -f pg-restore-test\n\n# Alert on failure\nif [ \"$USERS_COUNT\" -lt 1 ]; then\n  echo \"ALERT: Backup verification failed — users table is empty\" >&2\n  exit 1\nfi\n\necho \"[$(date)] Backup verification PASSED\"\n```\n\n## Unified Backup Script\n\n```bash\n#!\u002Fbin\u002Fbash\n# backup_all.sh — unified backup orchestrator\nset -euo pipefail\n\nLOG=\"\u002Fvar\u002Flog\u002Fbackup-all.log\"\nALERT_EMAIL=\"ops@example.com\"\nERRORS=0\n\nlog() { echo \"[$(date '+%F %T')] $*\" | tee -a \"$LOG\"; }\n\nrun_backup() {\n  local name=\"$1\" script=\"$2\"\n  log \"Starting $name backup...\"\n  if bash \"$script\" >> \"$LOG\" 2>&1; then\n    log \"$name backup succeeded.\"\n  else\n    log \"ERROR: $name backup FAILED.\"\n    ERRORS=$((ERRORS + 1))\n  fi\n}\n\nrun_backup \"PostgreSQL\" \u002Fopt\u002Fscripts\u002Fpg_backup.sh\nrun_backup \"MySQL\"      \u002Fopt\u002Fscripts\u002Fmysql_backup.sh\nrun_backup \"MongoDB\"    \u002Fopt\u002Fscripts\u002Fmongo_backup.sh\nrun_backup \"S3 Upload\"  \u002Fopt\u002Fscripts\u002Fs3_upload.sh\n\nif [ \"$ERRORS\" -gt 0 ]; then\n  log \"Backup run completed with $ERRORS error(s). Sending alert.\"\n  mail -s \"BACKUP ALERT: $ERRORS failure(s)\" \"$ALERT_EMAIL\" \u003C \"$LOG\"\n  exit 1\nfi\n\nlog \"All backups completed successfully.\"\n```\n\n## Best Practices\n\n- **3-2-1 Rule**: Keep 3 copies of data, on 2 different media types, with 1 offsite.\n- **Encrypt backups at rest**: Use `restic` (built-in encryption), AWS SSE, or `gpg`.\n- **Test restores regularly**: A backup that has never been restored is not a backup.\n- **Monitor backup jobs**: Alert immediately on any failure; do not rely on silent cron jobs.\n- **Document RTOs and RPOs**: Define Recovery Time Objective and Recovery Point Objective for each database.\n- **Version your backup scripts**: Store them in Git alongside your infrastructure code.\n- **Use `--single-transaction`**: For MySQL and PostgreSQL logical backups to get a consistent snapshot.\n- **Separate backup credentials**: Use a dedicated read-only database user for backups.\n\n## Troubleshooting\n\n| Symptom | Likely Cause | Fix |\n|---|---|---|\n| `pg_dump: too many clients` | Backup connection competes with app pool | Schedule during low traffic; increase `max_connections` by 5 for backup user |\n| `mysqldump` hangs on large table | Table lock contention | Use `--single-transaction` (InnoDB) or schedule during maintenance window |\n| `mongodump` slow on replica | Reading from secondary under load | Use `--readPreference=secondaryPreferred` and schedule off-peak |\n| S3 upload fails with timeout | Large file over slow connection | Use `aws s3 cp --expected-size` or multipart with `aws s3api` |\n| Restic prune takes hours | Too many snapshots accumulated | Run `restic forget --prune` more frequently; limit snapshot count |\n| Restore fails with \"role does not exist\" | Backup includes role-dependent objects | Create roles first or use `--no-owner --no-privileges` on restore |\n\n## Related Skills\n\n- postgresql (`postgresql-devsec`) - PostgreSQL administration and pg_dump details\n- mysql (`mysql`) - MySQL administration and mysqldump details\n- mongodb (`mongodb`) - MongoDB administration and mongodump details\n- redis (`redis`) - Redis RDB\u002FAOF persistence and backup\n\n## Limitations\n\n- Infrastructure commands can disrupt services: confirm target host\u002Fscope and have backups\u002Fsnapshots before mutating state.\n- Docs-only import: upstream scripts and templates not bundled.\n\n","# Database Backups\n\nImplement comprehensive, automated database backup strategies with tested recovery procedures.\n\n## When to Use\n\n- You are deploying a new database and need a backup plan from day one.\n- You need to automate nightly or hourly backups for PostgreSQL, MySQL, or MongoDB.\n- You want to ship backups to S3-compatible object storage with retention policies.\n- You are building or verifying disaster recovery runbooks.\n\n## Prerequisites\n\n- Database client tools installed (`pg_dump`, `mysqldump`, `mongodump`).\n- AWS CLI or `restic` for remote storage.\n- `cron` or systemd timers for scheduling.\n- An S3 bucket (or S3-compatible endpoint) for offsite backups.\n\n## Backup Types\n\n| Type | Description | Frequency | Use Case |\n|---|---|---|---|\n| Full | Complete database copy | Weekly | Baseline for restores |\n| Incremental | Changes since last backup | Daily | Reduce storage and time |\n| Transaction log \u002F WAL | Continuous log shipping | Continuous | Point-in-time recovery (PITR) |\n| Snapshot | Storage-level snapshot (EBS, ZFS) | Daily | Fast full restores |\n\n## PostgreSQL Backups\n\n### Logical Backup with pg_dump\n\n```bash\n#!\u002Fbin\u002Fbash\n# pg_backup.sh — PostgreSQL logical backup\nset -euo pipefail\n\nDB_NAME=\"mydb\"\nDB_USER=\"backup_user\"\nDB_HOST=\"localhost\"\nBACKUP_DIR=\"\u002Fbackups\u002Fpostgres\"\nDATE=$(date +%Y%m%d_%H%M%S)\nFILENAME=\"${BACKUP_DIR}\u002F${DB_NAME}_${DATE}.dump\"\n\nmkdir -p \"$BACKUP_DIR\"\n\n# Custom compressed format (recommended for selective restore)\npg_dump -h \"$DB_HOST\" -U \"$DB_USER\" -Fc -Z6 \"$DB_NAME\" > \"$FILENAME\"\n\necho \"[$(date)] PostgreSQL backup complete: $FILENAME ($(du -h \"$FILENAME\" | cut -f1))\"\n```\n\n### Physical Backup with pg_basebackup\n\n```bash\n#!\u002Fbin\u002Fbash\n# pg_basebackup.sh — PostgreSQL physical backup for PITR\nset -euo pipefail\n\nBACKUP_DIR=\"\u002Fbackups\u002Fpostgres\u002Fbase_$(date +%Y%m%d)\"\nmkdir -p \"$BACKUP_DIR\"\n\npg_basebackup \\\n  -h localhost \\\n  -U replicator \\\n  -D \"$BACKUP_DIR\" \\\n  --wal-method=stream \\\n  --checkpoint=fast \\\n  --progress \\\n  --verbose\n\necho \"[$(date)] Base backup complete: $BACKUP_DIR\"\n```\n\n### PostgreSQL Restore\n\n```bash\n# Restore from custom-format dump\npg_restore -h localhost -U myapp -d mydb --clean --if-exists \u002Fbackups\u002Fpostgres\u002Fmydb_20250115_020000.dump\n\n# Restore a single table\npg_restore -h localhost -U myapp -d mydb -t orders \u002Fbackups\u002Fpostgres\u002Fmydb_20250115_020000.dump\n\n# Restore from plain SQL\npsql -h localhost -U myapp -d mydb \u003C \u002Fbackups\u002Fpostgres\u002Fmydb_20250115.sql\n```\n\n## MySQL Backups\n\n### Logical Backup with mysqldump\n\n```bash\n#!\u002Fbin\u002Fbash\n# mysql_backup.sh — MySQL logical backup\nset -euo pipefail\n\nDB_NAME=\"mydb\"\nDB_USER=\"backup_user\"\nDB_PASS=\"${MYSQL_BACKUP_PASSWORD}\"\nBACKUP_DIR=\"\u002Fbackups\u002Fmysql\"\nDATE=$(date +%Y%m%d_%H%M%S)\nFILENAME=\"${BACKUP_DIR}\u002F${DB_NAME}_${DATE}.sql.gz\"\n\nmkdir -p \"$BACKUP_DIR\"\n\nmysqldump -u \"$DB_USER\" -p\"$DB_PASS\" \\\n  --single-transaction \\\n  --routines \\\n  --triggers \\\n  --events \\\n  \"$DB_NAME\" | gzip > \"$FILENAME\"\n\necho \"[$(date)] MySQL backup complete: $FILENAME ($(du -h \"$FILENAME\" | cut -f1))\"\n```\n\n### Physical Backup with Percona XtraBackup\n\n```bash\n#!\u002Fbin\u002Fbash\n# xtrabackup.sh — MySQL physical backup\nset -euo pipefail\n\nBACKUP_DIR=\"\u002Fbackups\u002Fmysql\u002Ffull_$(date +%Y%m%d)\"\n\nxtrabackup --backup \\\n  --user=backup_user \\\n  --password \"$MYSQL_BACKUP_PASSWORD\" # from your vault; never hardcode \\\n  --target-dir=\"$BACKUP_DIR\"\n\nxtrabackup --prepare --target-dir=\"$BACKUP_DIR\"\n\necho \"[$(date)] XtraBackup complete: $BACKUP_DIR\"\n```\n\n### MySQL Restore\n\n```bash\n# Restore from compressed mysqldump\ngunzip \u003C \u002Fbackups\u002Fmysql\u002Fmydb_20250115_020000.sql.gz | mysql -u root -p mydb\n\n# Restore from XtraBackup\nsudo systemctl stop mysql\nls \u002Fvar\u002Flib\u002Fmysql\u002F*  # verify this is the correct data dir first\nsudo find \u002Fvar\u002Flib\u002Fmysql -mindepth 1 -delete  # empty the data dir; snapshots must exist (see Limitations)\nxtrabackup --move-back --target-dir=\u002Fbackups\u002Fmysql\u002Ffull_20250115\nsudo chown -R mysql:mysql \u002Fvar\u002Flib\u002Fmysql\nsudo systemctl start mysql\n```\n\n## MongoDB Backups\n\n### Logical Backup with mongodump\n\n```bash\n#!\u002Fbin\u002Fbash\n# mongo_backup.sh — MongoDB backup\nset -euo pipefail\n\nMONGO_URI=\"mongodb:\u002F\u002Fbackup_user:${MONGO_BACKUP_PASSWORD}@localhost:27017\"\nBACKUP_DIR=\"\u002Fbackups\u002Fmongodb\"\nDATE=$(date +%Y%m%d_%H%M%S)\nTARGET=\"${BACKUP_DIR}\u002F${DATE}\"\n\nmkdir -p \"$BACKUP_DIR\"\n\n# Full backup with compression\nmongodump --uri=\"$MONGO_URI\" --gzip --out=\"$TARGET\"\n\necho \"[$(date)] MongoDB backup complete: $TARGET\"\n```\n\n### MongoDB Restore\n\n```bash\n# Restore all databases\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002F\n\n# Restore a single database\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop --db mydb \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002Fmydb\u002F\n\n# Restore a single collection\nmongorestore --uri=\"mongodb:\u002F\u002Fadmin:secret@localhost:27017\" \\\n  --gzip --drop --db mydb --collection users \\\n  \u002Fbackups\u002Fmongodb\u002F20250115_020000\u002Fmydb\u002Fusers.bson.gz\n```\n\n## Upload to S3\n\n```bash\n#!\u002Fbin\u002Fbash\n# s3_upload.sh — Upload backups to S3\nset -euo pipefail\n\nS3_BUCKET=\"s3:\u002F\u002Fmy-backups\"\nBACKUP_DIR=\"\u002Fbackups\"\nDATE=$(date +%Y%m%d)\n\n# Upload PostgreSQL backup\naws s3 cp \"${BACKUP_DIR}\u002Fpostgres\u002F\" \"${S3_BUCKET}\u002Fpostgres\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\n# Upload MySQL backup\naws s3 cp \"${BACKUP_DIR}\u002Fmysql\u002F\" \"${S3_BUCKET}\u002Fmysql\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\n# Upload MongoDB backup\naws s3 cp \"${BACKUP_DIR}\u002Fmongodb\u002F\" \"${S3_BUCKET}\u002Fmongodb\u002F${DATE}\u002F\" \\\n  --recursive --storage-class STANDARD_IA \\\n  --sse AES256\n\necho \"[$(date)] S3 upload complete for ${DATE}\"\n```\n\n### S3 Lifecycle Policy for Retention\n\n```json\n{\n  \"Rules\": [\n    {\n      \"ID\": \"BackupRetention\",\n      \"Status\": \"Enabled\",\n      \"Filter\": { \"Prefix\": \"\" },\n      \"Transitions\": [\n        { \"Days\": 30, \"StorageClass\": \"GLACIER\" }\n      ],\n      \"Expiration\": { \"Days\": 365 }\n    }\n  ]\n}\n```\n\n```bash\naws s3api put-bucket-lifecycle-configuration \\\n  --bucket my-backups \\\n  --lifecycle-configuration file:\u002F\u002Flifecycle.json\n```\n\n## Restic Backup (Encrypted, Deduplicated)\n\n```bash\n# Initialize a restic repository on S3\nexport AWS_ACCESS_KEY_ID=\"AKIA...\"\nexport AWS_SECRET_ACCESS_KEY=\"...\"\nexport RESTIC_PASSWORD=\"...\" # set a strong restic password via your vault\nexport RESTIC_REPOSITORY=\"s3:s3.amazonaws.com\u002Fmy-backups-restic\"\n\nrestic init\n\n# Backup the local backup directory\nrestic backup \u002Fbackups\u002Fpostgres \u002Fbackups\u002Fmysql \u002Fbackups\u002Fmongodb\n\n# List snapshots\nrestic snapshots\n\n# Prune old snapshots — keep 7 daily, 4 weekly, 6 monthly\nrestic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune\n\n# Restore a snapshot\nrestic restore latest --target \u002Frestore\u002F\n```\n\n## Cron Schedules\n\n```bash\n# \u002Fetc\u002Fcron.d\u002Fdb-backups\n\n# PostgreSQL: nightly at 02:00\n0 2 * * * backup \u002Fopt\u002Fscripts\u002Fpg_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-pg.log 2>&1\n\n# MySQL: nightly at 02:30\n30 2 * * * backup \u002Fopt\u002Fscripts\u002Fmysql_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-mysql.log 2>&1\n\n# MongoDB: nightly at 03:00\n0 3 * * * backup \u002Fopt\u002Fscripts\u002Fmongo_backup.sh >> \u002Fvar\u002Flog\u002Fbackup-mongo.log 2>&1\n\n# Upload to S3: daily at 04:00\n0 4 * * * backup \u002Fopt\u002Fscripts\u002Fs3_upload.sh >> \u002Fvar\u002Flog\u002Fbackup-s3.log 2>&1\n\n# Local cleanup: keep 7 days of local backups\n0 5 * * * backup find \u002Fbackups -type f -mtime +7 -delete >> \u002Fvar\u002Flog\u002Fbackup-cleanup.log 2>&1\n\n# Restic prune: weekly on Sunday at 06:00\n0 6 * * 0 backup \u002Fopt\u002Fscripts\u002Frestic_prune.sh >> \u002Fvar\u002Flog\u002Fbackup-restic.log 2>&1\n```\n\n## Automated Recovery Testing\n\n```bash\n#!\u002Fbin\u002Fbash\n# verify_backup.sh — weekly restore test\nset -euo pipefail\n\nBACKUP_FILE=$(ls -t \u002Fbackups\u002Fpostgres\u002Fmydb_*.dump | head -1)\n\necho \"[$(date)] Starting backup verification with $BACKUP_FILE\"\n\n# Spin up a temporary PostgreSQL container\ndocker run -d --name pg-restore-test \\\n  -e POSTGRES_USER=testuser \\\n  -e POSTGRES_PASSWORD=testpass \\\n  -e POSTGRES_DB=testdb \\\n  postgres:16-alpine\n\n# Wait for container to be ready\nsleep 5\nuntil docker exec pg-restore-test pg_isready -U testuser; do\n  sleep 2\ndone\n\n# Copy backup into container and restore\ndocker cp \"$BACKUP_FILE\" pg-restore-test:\u002Ftmp\u002Fbackup.dump\ndocker exec pg-restore-test pg_restore -U testuser -d testdb --clean --if-exists \u002Ftmp\u002Fbackup.dump\n\n# Run verification queries\nUSERS_COUNT=$(docker exec pg-restore-test psql -U testuser -d testdb -tAc \"SELECT COUNT(*) FROM users;\")\nORDERS_COUNT=$(docker exec pg-restore-test psql -U testuser -d testdb -tAc \"SELECT COUNT(*) FROM orders;\")\n\necho \"[$(date)] Verification: users=$USERS_COUNT, orders=$ORDERS_COUNT\"\n\n# Cleanup\ndocker rm -f pg-restore-test\n\n# Alert on failure\nif [ \"$USERS_COUNT\" -lt 1 ]; then\n  echo \"ALERT: Backup verification failed — users table is empty\" >&2\n  exit 1\nfi\n\necho \"[$(date)] Backup verification PASSED\"\n```\n\n## Unified Backup Script\n\n```bash\n#!\u002Fbin\u002Fbash\n# backup_all.sh — unified backup orchestrator\nset -euo pipefail\n\nLOG=\"\u002Fvar\u002Flog\u002Fbackup-all.log\"\nALERT_EMAIL=\"ops@example.com\"\nERRORS=0\n\nlog() { echo \"[$(date '+%F %T')] $*\" | tee -a \"$LOG\"; }\n\nrun_backup() {\n  local name=\"$1\" script=\"$2\"\n  log \"Starting $name backup...\"\n  if bash \"$script\" >> \"$LOG\" 2>&1; then\n    log \"$name backup succeeded.\"\n  else\n    log \"ERROR: $name backup FAILED.\"\n    ERRORS=$((ERRORS + 1))\n  fi\n}\n\nrun_backup \"PostgreSQL\" \u002Fopt\u002Fscripts\u002Fpg_backup.sh\nrun_backup \"MySQL\"      \u002Fopt\u002Fscripts\u002Fmysql_backup.sh\nrun_backup \"MongoDB\"    \u002Fopt\u002Fscripts\u002Fmongo_backup.sh\nrun_backup \"S3 Upload\"  \u002Fopt\u002Fscripts\u002Fs3_upload.sh\n\nif [ \"$ERRORS\" -gt 0 ]; then\n  log \"Backup run completed with $ERRORS error(s). Sending alert.\"\n  mail -s \"BACKUP ALERT: $ERRORS failure(s)\" \"$ALERT_EMAIL\" \u003C \"$LOG\"\n  exit 1\nfi\n\nlog \"All backups completed successfully.\"\n```\n\n## Best Practices\n\n- **3-2-1 Rule**: Keep 3 copies of data, on 2 different media types, with 1 offsite.\n- **Encrypt backups at rest**: Use `restic` (built-in encryption), AWS SSE, or `gpg`.\n- **Test restores regularly**: A backup that has never been restored is not a backup.\n- **Monitor backup jobs**: Alert immediately on any failure; do not rely on silent cron jobs.\n- **Document RTOs and RPOs**: Define Recovery Time Objective and Recovery Point Objective for each database.\n- **Version your backup scripts**: Store them in Git alongside your infrastructure code.\n- **Use `--single-transaction`**: For MySQL and PostgreSQL logical backups to get a consistent snapshot.\n- **Separate backup credentials**: Use a dedicated read-only database user for backups.\n\n## Troubleshooting\n\n| Symptom | Likely Cause | Fix |\n|---|---|---|\n| `pg_dump: too many clients` | Backup connection competes with app pool | Schedule during low traffic; increase `max_connections` by 5 for backup user |\n| `mysqldump` hangs on large table | Table lock contention | Use `--single-transaction` (InnoDB) or schedule during maintenance window |\n| `mongodump` slow on replica | Reading from secondary under load | Use `--readPreference=secondaryPreferred` and schedule off-peak |\n| S3 upload fails with timeout | Large file over slow connection | Use `aws s3 cp --expected-size` or multipart with `aws s3api` |\n| Restic prune takes hours | Too many snapshots accumulated | Run `restic forget --prune` more frequently; limit snapshot count |\n| Restore fails with \"role does not exist\" | Backup includes role-dependent objects | Create roles first or use `--no-owner --no-privileges` on restore |\n\n## Related Skills\n\n- postgresql (`postgresql-devsec`) - PostgreSQL administration and pg_dump details\n- mysql (`mysql`) - MySQL administration and mysqldump details\n- mongodb (`mongodb`) - MongoDB administration and mongodump details\n- redis (`redis`) - Redis RDB\u002FAOF persistence and backup\n\n## Limitations\n\n- Infrastructure commands can disrupt services: confirm target host\u002Fscope and have backups\u002Fsnapshots before mutating state.\n- Docs-only import: upstream scripts and templates not bundled.\n\n",{"name":5,"risk":32,"source":51,"license":14,"category":52,"metadata":53,"date_added":56,"description":7,"source_repo":57,"source_type":28,"compatibility":58,"license_source":59},"https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills","devops",{"author":54,"version":55},"devops-skills","1.0","2026-09-20","BagelHole\u002FDevOps-Security-Agent-Skills","Requires the relevant OS\u002Fplatform tooling and privileged access where noted. Docs-only; helper scripts and templates not bundled.","https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE","f3312ba749561b6159f477dbfc9313c875d40a56",".agents\u002Fskills_archive\u002Fdatabase-backups","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612","2026-10-25 23:50:58",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill database-backups",{"tool":71,"command":72},"bunx","bunx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill database-backups",{"tool":74,"command":75},"pnpm","pnpm dlx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill database-backups","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fdatabase-backups\u002FSKILL.md",true,[],[80,100,124,148,174,198],{"skillNo":81,"name":82,"nameZh":6,"description":83,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":84,"categories":85,"keywords":89,"publishedAt":46},"01M6Q0FA5FZ410Z33Z3TFQ4DBA","zero-trust","Implement zero-trust network architecture. Configure identity-based access, micro-segmentation, and continuous verification. Use when implementing modern security architectures.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzero-trust\u002FSKILL.md",[86],{"categoryNo":87,"categoryName":88,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000011","运维与部署",[90,91,92,93,94,95,82,96,43,42,41,39,28,36,97,32,98,31,29,99],"ZeRO","trust","zero trust","architecture","assessment","verification","segmentation","active","scope","implementing",{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":46},"01M6Q0F1YZJW3KX5FBKEVZ8CV4","zcode-delegate","Delegate coding tasks to the Z.AI ZCode CLI only when the user explicitly requests it, while the orchestrator retains review and landing responsibility.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzcode-delegate\u002FSKILL.md",[],[107,108,109,110,111,112,113,114,115,116,117,118,119,39,120,28,121,122,32,123],"delegate","zcode","zcode delegate","review","cli","orchestration","tasks","run","Bash","model","node","read","orchestrator","files","desktop app","app","agent-orchestration",{"skillNo":125,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":130,"publishedAt":46},"01M6Q0ETK41VGNMYEXW0T00AJN","youtube-transcript","Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript\u002FSKILL.md",[],[131,132,133,134,135,136,137,44,138,139,140,141,142,28,36,143,144,145,146,147],"transcript","youtube transcript","youtube","safe","github","codex","research","https","text","fetch","tooling","clean","local","output","deepapi","youtube transcripts","blob",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":163,"publishedAt":46},"01M6Q0EPPH2PVMDW40017F8WX0","youtube-transcript-skills","Fetch YouTube video transcripts, search videos\u002Fchannels, browse channels, and extract playlists via the getyoutubetranscript.com API - free tier, no card required.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript-skills\u002FSKILL.md",[154,155,158],{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":156,"categoryName":157,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":159,"categoryName":160,"taxonomyType":161,"taxonomyTypeDesc":162},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[131,132,133,164,134,165,135,136,44,166,167,168,169,140,170,28,36,171,172,173],"youtube transcript skills","gemini","search","api","Video","browse","api-integration","free","card","channels",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":184,"publishedAt":46},"01M6Q0EAB96PX83W5PTE8A0R8D","youtube-notetaker","Turn YouTube talks into local study notes with slides, transcripts, editable annotations, and a markdown-backed viewer.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-notetaker\u002FSKILL.md",[180,183],{"categoryNo":181,"categoryName":182,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":156,"categoryName":157,"taxonomyType":20,"taxonomyTypeDesc":21},[133,185,186,111,134,187,188,189,190,44,168,191,192,193,194,36,195,143,196,197],"youtube notetaker","notetaker","workflow","official","notes","code","markdown","slides","annotations","README","study","dair-academy","viewer",{"skillNo":199,"name":200,"nameZh":6,"description":201,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":202,"categories":203,"keywords":205,"publishedAt":46},"01M6Q0E55F0GW5MX48V8HXS8B5","youtube-full","Fetch YouTube transcripts, search videos, browse channels, and extract playlists via TranscriptAPI — no yt-dlp, no Google API key, works from any cloud server.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-full\u002FSKILL.md",[204],{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},[206,133,207,208,134,165,166,209,210,167,168,169,140,211,170,28,36,171,212,146],"youtube full","full","google","server","dlp","credits","automatic"]