Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • šŸ“ Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • šŸ“ Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • šŸ“ Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • šŸ“ Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • šŸ“ While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • šŸ“ For Each Assignments
    • šŸ“ All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • šŸ“ Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • šŸ“ Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • šŸ“ Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • šŸ“ Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • šŸ“ Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • šŸ“ Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • šŸ“ Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • šŸ“ Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • šŸ“ Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • šŸ“ Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • šŸ“ Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • šŸ“ Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • šŸ“ Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • šŸ“ Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • šŸ“ Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • šŸ“ Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • šŸ“ Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • šŸ“ Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • šŸ“ Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Backup MySQL Database

Python MySQL Backup - Complete Guide

Learn how to backup and protect your MySQL databases using Python.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
On this page:
  • Why Backup Your Database?
  • Backup Methods
  • Using mysqldump
  • Python Backup Script
  • Automating Backups
  • Restoring from Backup
  • Real-World Example
  • Best Practices
  • Try It Yourself
  • Quiz
  • FAQ
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • Why backup matters — protecting your data
  • Backup methods — different ways to backup
  • Using mysqldump — the standard backup tool
  • Python backup script — automating backups
  • Automation — scheduling regular backups
  • Restoring — recovering from backups

Why Backup Your Database?

Backing up your database is one of the most important things you can do as a developer. Data loss can happen in many ways — accidental deletion, server crashes, corruption, or even security breaches.

āš ļø Without a backup, recovering lost data can be impossible.

Imagine losing all your customer data, order history, or user accounts. A good backup strategy is your safety net.

Think of a database backup like a copy of your important files. You wouldn't keep only one copy of a crucial document, right? The same applies to your database.

1

What Can Go Wrong?

# ============================================================
# REAL-WORLD SCENARIOS
# ============================================================

print("""
1. Human Error
   - Developer accidentally deletes a table
   - User runs wrong UPDATE statement
   - Wrong data is inserted

2. System Failures
   - Server crashes
   - Hard disk fails
   - Power outages

3. Security Issues
   - Data breaches
   - Ransomware attacks
   - SQL injection

4. Application Bugs
   - Bug corrupts data
   - Migration goes wrong
   - Data inconsistency

5. Natural Disasters
   - Fire, flood, earthquake
   - Hardware destruction
   - Data center issues

šŸ’€ ANY of these can happen to you!
āœ… A backup protects you from ALL of them!
""")

Key point: Backups are not optional — they're essential for any production application.

Quick Check: Why are database backups important? (Answer: They protect against data loss from accidents, failures, and security issues)

Backup Methods

2

Different Ways to Backup Your Database

Method Description Pros Cons
mysqldump Official MySQL backup tool Standard, reliable, portable Slow for large databases
MySQL Shell Advanced MySQL utility Fast, supports parallelism More complex to use
File Copy Copy database files directly Very fast Requires downtime
Replication Maintain a live replica Real-time backup Complex setup
Cloud Backup AWS RDS, Google Cloud SQL Managed, automated Can be expensive

For most users, mysqldump is the best choice — it's reliable, well-supported, and easy to automate with Python.

Quick Check: What is the most commonly used MySQL backup tool? (Answer: mysqldump)

Using mysqldump

3

The Standard MySQL Backup Tool

# ============================================================
# MYSQLDUMP BASIC COMMANDS
# ============================================================

# 1. Backup a single database
mysqldump -u root -p myapp_db > backup.sql

# 2. Backup with username and password
mysqldump -u root -psecret myapp_db > backup.sql

# 3. Backup multiple databases
mysqldump -u root -p --databases db1 db2 db3 > backup.sql

# 4. Backup all databases
mysqldump -u root -p --all-databases > backup.sql

# 5. Backup with compression
mysqldump -u root -p myapp_db | gzip > backup.sql.gz

# 6. Backup specific tables
mysqldump -u root -p myapp_db table1 table2 > backup.sql

# 7. Backup only structure (no data)
mysqldump -u root -p --no-data myapp_db > structure.sql

# 8. Backup only data (no structure)
mysqldump -u root -p --no-create-info myapp_db > data.sql

# 9. Backup with timestamp
mysqldump -u root -p myapp_db > backup_$(date +%Y%m%d).sql

# ============================================================
# RUNNING MYSQLDUMP FROM PYTHON
# ============================================================

import subprocess
import datetime

def backup_database(db_name, user, password, backup_dir):
    """Backup a MySQL database using mysqldump"""
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"{backup_dir}/{db_name}_{timestamp}.sql"
    
    command = f"mysqldump -u {user} -p{password} {db_name} > {filename}"
    
    try:
        subprocess.run(command, shell=True, check=True)
        print(f"āœ… Backup created: {filename}")
        return filename
    except subprocess.CalledProcessError as e:
        print(f"āŒ Backup failed: {e}")
        return None

# Usage
backup_database("myapp_db", "root", "secret", "/backups")

mysqldump key points:

  • Creates a SQL script that can recreate the database
  • Can backup structure, data, or both
  • Supports compression for large databases
  • Can be automated from Python

Quick Check: What does mysqldump produce? (Answer: A SQL script that can recreate the database)

Python Backup Script

4

Building a Complete Backup Script

# ============================================================
# COMPLETE PYTHON BACKUP SCRIPT
# ============================================================

import subprocess
import os
import datetime
import gzip
import shutil
import logging

# Set up logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('backup.log'),
        logging.StreamHandler()
    ]
)

class MySQLBackup:
    """MySQL database backup utility"""
    
    def __init__(self, host, user, password, backup_dir):
        self.host = host
        self.user = user
        self.password = password
        self.backup_dir = backup_dir
        self.logger = logging.getLogger(__name__)
        
        # Create backup directory if it doesn't exist
        os.makedirs(backup_dir, exist_ok=True)
    
    def backup_database(self, db_name, compress=True, keep_days=7):
        """Backup a single database"""
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"{db_name}_{timestamp}.sql"
        filepath = os.path.join(self.backup_dir, filename)
        
        # Build mysqldump command
        cmd = [
            "mysqldump",
            f"--host={self.host}",
            f"--user={self.user}",
            f"--password={self.password}",
            "--single-transaction",  # For InnoDB consistency
            "--routines",  # Include stored procedures
            "--triggers",  # Include triggers
            db_name
        ]
        
        try:
            self.logger.info(f"Starting backup of {db_name}")
            
            # Run mysqldump
            with open(filepath, 'w') as f:
                subprocess.run(cmd, stdout=f, check=True)
            
            # Compress if requested
            if compress:
                compressed_path = filepath + '.gz'
                with open(filepath, 'rb') as f_in:
                    with gzip.open(compressed_path, 'wb') as f_out:
                        shutil.copyfileobj(f_in, f_out)
                os.remove(filepath)  # Remove uncompressed
                filepath = compressed_path
            
            self.logger.info(f"āœ… Backup created: {filepath}")
            
            # Clean old backups
            self._clean_old_backups(db_name, keep_days)
            
            return filepath
            
        except subprocess.CalledProcessError as e:
            self.logger.error(f"āŒ Backup failed: {e}")
            if os.path.exists(filepath):
                os.remove(filepath)
            return None
        except Exception as e:
            self.logger.error(f"āŒ Error: {e}")
            return None
    
    def backup_multiple(self, db_names, compress=True, keep_days=7):
        """Backup multiple databases"""
        results = {}
        for db_name in db_names:
            results[db_name] = self.backup_database(db_name, compress, keep_days)
        return results
    
    def backup_all_databases(self, compress=True, keep_days=7):
        """Backup all databases"""
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"all_databases_{timestamp}.sql"
        filepath = os.path.join(self.backup_dir, filename)
        
        cmd = [
            "mysqldump",
            f"--host={self.host}",
            f"--user={self.user}",
            f"--password={self.password}",
            "--all-databases",
            "--single-transaction",
            "--routines",
            "--triggers"
        ]
        
        try:
            self.logger.info("Starting backup of all databases")
            
            with open(filepath, 'w') as f:
                subprocess.run(cmd, stdout=f, check=True)
            
            if compress:
                compressed_path = filepath + '.gz'
                with open(filepath, 'rb') as f_in:
                    with gzip.open(compressed_path, 'wb') as f_out:
                        shutil.copyfileobj(f_in, f_out)
                os.remove(filepath)
                filepath = compressed_path
            
            self.logger.info(f"āœ… Full backup created: {filepath}")
            
            # Clean old backups
            self._clean_old_backups("all_databases", keep_days)
            
            return filepath
            
        except Exception as e:
            self.logger.error(f"āŒ Backup failed: {e}")
            return None
    
    def _clean_old_backups(self, prefix, keep_days):
        """Delete old backup files"""
        try:
            now = datetime.datetime.now()
            cutoff = now - datetime.timedelta(days=keep_days)
            
            for filename in os.listdir(self.backup_dir):
                if filename.startswith(prefix):
                    filepath = os.path.join(self.backup_dir, filename)
                    mtime = datetime.datetime.fromtimestamp(os.path.getmtime(filepath))
                    
                    if mtime < cutoff:
                        os.remove(filepath)
                        self.logger.info(f"šŸ—‘ļø Removed old backup: {filename}")
                        
        except Exception as e:
            self.logger.warning(f"Failed to clean old backups: {e}")
    
    def get_backup_size(self, filepath):
        """Get the size of a backup file"""
        if os.path.exists(filepath):
            size = os.path.getsize(filepath)
            if size < 1024:
                return f"{size} B"
            elif size < 1024 * 1024:
                return f"{size / 1024:.2f} KB"
            else:
                return f"{size / (1024 * 1024):.2f} MB"
        return "File not found"
    
    def list_backups(self):
        """List all backup files"""
        backups = []
        for filename in os.listdir(self.backup_dir):
            if filename.endswith('.sql') or filename.endswith('.sql.gz'):
                filepath = os.path.join(self.backup_dir, filename)
                mtime = datetime.datetime.fromtimestamp(os.path.getmtime(filepath))
                backups.append({
                    'name': filename,
                    'path': filepath,
                    'size': self.get_backup_size(filepath),
                    'modified': mtime
                })
        return sorted(backups, key=lambda x: x['modified'], reverse=True)

# ============================================================
# USAGE EXAMPLE
# ============================================================

if __name__ == "__main__":
    backup = MySQLBackup(
        host="localhost",
        user="root",
        password="secret",
        backup_dir="./backups"
    )
    
    # Backup a single database
    backup.backup_database("myapp_db")
    
    # Backup multiple databases
    backup.backup_multiple(["myapp_db", "test_db"])
    
    # Backup all databases
    backup.backup_all_databases()
    
    # List backups
    print("\nšŸ“‹ Available backups:")
    for b in backup.list_backups()[:5]:
        print(f"  {b['name']} - {b['size']} - {b['modified']}")

This script provides:

  • Single and multiple database backup
  • Compression support
  • Automatic cleanup of old backups
  • Logging for tracking
  • Backup listing and size information

Quick Check: What Python module is used to run mysqldump? (Answer: subprocess)

Automating Backups

5

Scheduling Regular Backups

# ============================================================
# AUTOMATED BACKUP SCHEDULER
# ============================================================

import schedule
import time
import smtplib
from email.mime.text import MIMEText

class BackupScheduler:
    """Schedule and automate database backups"""
    
    def __init__(self, backup_utility, email_config=None):
        self.backup = backup_utility
        self.email_config = email_config
    
    def daily_backup(self):
        """Run daily backup"""
        print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Starting daily backup...")
        result = self.backup.backup_all_databases()
        
        if result:
            print(f"āœ… Daily backup completed: {result}")
            self._send_notification("Daily backup successful", result)
        else:
            print("āŒ Daily backup failed")
            self._send_notification("Daily backup FAILED", "Check logs for details")
    
    def weekly_backup(self):
        """Run weekly full backup with verification"""
        print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] Starting weekly backup...")
        
        # Backup all databases
        result = self.backup.backup_all_databases()
        
        if result:
            # Verify backup size
            size = self.backup.get_backup_size(result)
            print(f"āœ… Weekly backup completed: {result} ({size})")
            self._send_notification("Weekly backup successful", f"{result} ({size})")
        else:
            print("āŒ Weekly backup failed")
            self._send_notification("Weekly backup FAILED", "Check logs for details")
    
    def _send_notification(self, subject, message):
        """Send email notification"""
        if not self.email_config:
            return
        
        try:
            msg = MIMEText(message)
            msg['Subject'] = f"Backup Notification: {subject}"
            msg['From'] = self.email_config['from']
            msg['To'] = self.email_config['to']
            
            with smtplib.SMTP(self.email_config['smtp_server'], self.email_config['smtp_port']) as server:
                server.starttls()
                server.login(self.email_config['username'], self.email_config['password'])
                server.send_message(msg)
                
            print(f"šŸ“§ Notification sent: {subject}")
            
        except Exception as e:
            print(f"Failed to send notification: {e}")
    
    def run_scheduler(self):
        """Run the scheduler"""
        # Schedule backups
        schedule.every().day.at("02:00").do(self.daily_backup)
        schedule.every().sunday.at("03:00").do(self.weekly_backup)
        
        print("šŸ”„ Backup scheduler started")
        print("šŸ“… Daily backup at 2:00 AM")
        print("šŸ“… Weekly backup on Sunday at 3:00 AM")
        print("Press Ctrl+C to stop")
        
        try:
            while True:
                schedule.run_pending()
                time.sleep(60)  # Check every minute
        except KeyboardInterrupt:
            print("\nā¹ļø Scheduler stopped")

# ============================================================
# CONFIGURATION FILE
# ============================================================

# config.json
{
    "mysql": {
        "host": "localhost",
        "user": "root",
        "password": "secret"
    },
    "backup": {
        "directory": "/backups",
        "keep_days": 30
    },
    "email": {
        "smtp_server": "smtp.gmail.com",
        "smtp_port": 587,
        "username": "alerts@example.com",
        "password": "app_password",
        "from": "alerts@example.com",
        "to": "admin@example.com"
    }
}

# ============================================================
# RUNNING THE SCHEDULER
# ============================================================

if __name__ == "__main__":
    # Load config (simplified)
    backup = MySQLBackup("localhost", "root", "secret", "/backups")
    scheduler = BackupScheduler(backup)
    scheduler.run_scheduler()

Automation features:

  • Daily backups — for regular data protection
  • Weekly backups — for full verification
  • Email notifications — alerts on success/failure
  • Configurable timing — run when convenient

Quick Check: What library is used for scheduling? (Answer: schedule)

Restoring from Backup

6

Recovering Your Data

āš ļø Restoring a database replaces all existing data.

Always verify which database you're restoring and ensure you have a recent backup before restoring.

# ============================================================
# RESTORING FROM BACKUP
# ============================================================

import subprocess
import gzip
import os

class MySQLRestore:
    """Restore MySQL databases from backups"""
    
    def __init__(self, host, user, password):
        self.host = host
        self.user = user
        self.password = password
    
    def restore_database(self, backup_file, db_name=None):
        """Restore a database from a backup file"""
        if not os.path.exists(backup_file):
            print(f"āŒ Backup file not found: {backup_file}")
            return False
        
        try:
            # Determine if backup is compressed
            if backup_file.endswith('.gz'):
                # Decompress on the fly
                cmd = f"gunzip -c {backup_file} | mysql -u {self.user} -p{self.password}"
                if db_name:
                    cmd += f" {db_name}"
            else:
                # Direct restore
                cmd = f"mysql -u {self.user} -p{self.password}"
                if db_name:
                    cmd += f" {db_name}"
                cmd += f" < {backup_file}"
            
            print(f"šŸ”„ Restoring from: {backup_file}")
            if db_name:
                print(f"šŸ“Š Database: {db_name}")
            
            subprocess.run(cmd, shell=True, check=True)
            print(f"āœ… Restore successful!")
            return True
            
        except subprocess.CalledProcessError as e:
            print(f"āŒ Restore failed: {e}")
            return False
        except Exception as e:
            print(f"āŒ Error: {e}")
            return False
    
    def restore_with_confirmation(self, backup_file, db_name=None):
        """Restore with user confirmation"""
        print("\nāš ļø WARNING: This will overwrite the database!")
        print(f"šŸ“ Backup: {backup_file}")
        if db_name:
            print(f"šŸ“Š Database: {db_name}")
        
        confirm = input("Are you sure you want to restore? (type 'YES' to proceed): ")
        if confirm == 'YES':
            return self.restore_database(backup_file, db_name)
        else:
            print("āŒ Restore cancelled")
            return False

# ============================================================
# USAGE EXAMPLE
# ============================================================

restore = MySQLRestore("localhost", "root", "secret")

# Restore a database
restore.restore_database("/backups/myapp_db_20240115.sql", "myapp_db")

# Restore from compressed backup
restore.restore_database("/backups/all_databases_20240115.sql.gz")

# Restore with confirmation
restore.restore_with_confirmation("/backups/myapp_db_20240115.sql", "myapp_db")

Restore key points:

  • Always confirm before restoring
  • Supports compressed backup files
  • Can restore to a different database name
  • Overwrites existing data

Quick Check: What command is used to restore a backup? (Answer: mysql command with the backup file)

Real-World Example: Production Backup System

7

Complete Production Backup System

# ============================================================
# PRODUCTION BACKUP SYSTEM
# ============================================================

import os
import datetime
import json
import logging
import subprocess
import shutil

class ProductionBackupSystem:
    """Complete backup system for production environments"""
    
    def __init__(self, config_file):
        self.config = self._load_config(config_file)
        self.setup_logging()
        self.logger = logging.getLogger(__name__)
    
    def _load_config(self, config_file):
        """Load configuration from JSON file"""
        with open(config_file, 'r') as f:
            return json.load(f)
    
    def setup_logging(self):
        """Set up logging configuration"""
        log_dir = self.config.get('logging', {}).get('directory', './logs')
        os.makedirs(log_dir, exist_ok=True)
        
        log_file = os.path.join(log_dir, f"backup_{datetime.datetime.now().strftime('%Y%m%d')}.log")
        
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file),
                logging.StreamHandler()
            ]
        )
    
    def backup(self, backup_type='full'):
        """Run backup based on type"""
        self.logger.info(f"Starting {backup_type} backup")
        
        # Get backup directory
        backup_base = self.config['backup']['directory']
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # Create backup directory
        if backup_type == 'full':
            backup_dir = os.path.join(backup_base, f"full_{timestamp}")
        else:
            backup_dir = os.path.join(backup_base, f"daily_{timestamp}")
        
        os.makedirs(backup_dir, exist_ok=True)
        
        try:
            # Backup each database
            for db_config in self.config['databases']:
                db_name = db_config['name']
                self._backup_database(db_name, backup_dir)
            
            # Create metadata
            self._create_metadata(backup_dir, backup_type)
            
            # Compress the entire backup
            self._compress_backup(backup_dir)
            
            # Clean old backups
            self._clean_old_backups(backup_base, backup_type)
            
            # Verify backup
            self._verify_backup(backup_dir + '.tar.gz')
            
            self.logger.info(f"āœ… {backup_type} backup completed successfully")
            return True
            
        except Exception as e:
            self.logger.error(f"āŒ {backup_type} backup failed: {e}")
            return False
    
    def _backup_database(self, db_name, backup_dir):
        """Backup a single database"""
        db_config = next(
            (db for db in self.config['databases'] if db['name'] == db_name),
            None
        )
        
        if not db_config:
            self.logger.warning(f"Database {db_name} not in config")
            return
        
        self.logger.info(f"šŸ“Š Backing up: {db_name}")
        
        # Build mysqldump command
        cmd = [
            "mysqldump",
            f"--host={self.config['mysql']['host']}",
            f"--user={self.config['mysql']['user']}",
            f"--password={self.config['mysql']['password']}",
            "--single-transaction",
            "--routines",
            "--triggers",
            db_name
        ]
        
        # Add options for specific databases
        if db_config.get('options'):
            cmd.extend(db_config['options'])
        
        # Output file
        backup_file = os.path.join(backup_dir, f"{db_name}.sql")
        
        with open(backup_file, 'w') as f:
            subprocess.run(cmd, stdout=f, check=True)
        
        self.logger.info(f"   āœ… {db_name} backed up to {backup_file}")
    
    def _create_metadata(self, backup_dir, backup_type):
        """Create metadata file for the backup"""
        metadata = {
            'backup_type': backup_type,
            'timestamp': datetime.datetime.now().isoformat(),
            'host': self.config['mysql']['host'],
            'databases': [db['name'] for db in self.config['databases']],
            'server_info': self._get_server_info()
        }
        
        metadata_file = os.path.join(backup_dir, 'metadata.json')
        with open(metadata_file, 'w') as f:
            json.dump(metadata, f, indent=2)
        
        self.logger.info(f"šŸ“‹ Metadata created: {metadata_file}")
    
    def _get_server_info(self):
        """Get MySQL server information"""
        try:
            cmd = [
                "mysql",
                f"--host={self.config['mysql']['host']}",
                f"--user={self.config['mysql']['user']}",
                f"--password={self.config['mysql']['password']}",
                "-e", "SELECT VERSION()"
            ]
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)
            return {'version': result.stdout.strip().split('\n')[1]}
        except:
            return {'version': 'Unknown'}
    
    def _compress_backup(self, backup_dir):
        """Compress the backup directory"""
        import tarfile
        
        tar_file = backup_dir + '.tar.gz'
        self.logger.info(f"šŸ“¦ Compressing backup: {tar_file}")
        
        with tarfile.open(tar_file, 'w:gz') as tar:
            tar.add(backup_dir, arcname=os.path.basename(backup_dir))
        
        # Remove uncompressed directory
        shutil.rmtree(backup_dir)
        
        self.logger.info(f"   āœ… Compressed to: {tar_file}")
        return tar_file
    
    def _clean_old_backups(self, backup_base, backup_type):
        """Clean old backups based on retention policy"""
        retention = self.config['backup'].get('retention', {})
        
        if backup_type == 'full':
            days = retention.get('full', 30)
            prefix = 'full_'
        else:
            days = retention.get('daily', 7)
            prefix = 'daily_'
        
        self.logger.info(f"šŸ—‘ļø Cleaning backups older than {days} days")
        
        now = datetime.datetime.now()
        cutoff = now - datetime.timedelta(days=days)
        
        for item in os.listdir(backup_base):
            if item.startswith(prefix) and item.endswith('.tar.gz'):
                item_path = os.path.join(backup_base, item)
                mtime = datetime.datetime.fromtimestamp(os.path.getmtime(item_path))
                
                if mtime < cutoff:
                    os.remove(item_path)
                    self.logger.info(f"   šŸ—‘ļø Removed old backup: {item}")
    
    def _verify_backup(self, backup_file):
        """Verify the backup file integrity"""
        self.logger.info(f"šŸ” Verifying backup: {backup_file}")
        
        if not os.path.exists(backup_file):
            self.logger.error("āŒ Backup file not found")
            return False
        
        # Check file size
        size = os.path.getsize(backup_file)
        if size < 1024:
            self.logger.error(f"āŒ Backup file too small: {size} bytes")
            return False
        
        self.logger.info(f"   āœ… Backup verified: {size / (1024*1024):.2f} MB")
        return True
    
    def run(self):
        """Run the backup system"""
        print("\n" + "=" * 60)
        print("PRODUCTION BACKUP SYSTEM")
        print("=" * 60)
        
        # Run full backup weekly, daily backup otherwise
        if datetime.datetime.now().weekday() == 0:  # Monday
            self.backup('full')
        else:
            self.backup('daily')

# ============================================================
# CONFIGURATION FILE (config.json)
# ============================================================

# {
#     "mysql": {
#         "host": "localhost",
#         "user": "root",
#         "password": "secret"
#     },
#     "databases": [
#         {"name": "myapp_db", "options": ["--no-data"]},
#         {"name": "user_db"},
#         {"name": "order_db"}
#     ],
#     "backup": {
#         "directory": "/backups",
#         "retention": {
#             "daily": 7,
#             "full": 30
#         }
#     },
#     "logging": {
#         "directory": "/logs"
#     }
# }

# ============================================================
# RUNNING THE SYSTEM
# ============================================================

if __name__ == "__main__":
    backup_system = ProductionBackupSystem("config.json")
    backup_system.run()

This production system includes:

  • JSON configuration for easy management
  • Full and daily backup strategies
  • Automatic cleanup based on retention policy
  • Compression to save space
  • Verification to ensure backup integrity
  • Comprehensive logging
  • Metadata for tracking

Quick Check: What is the purpose of retention policy? (Answer: To automatically remove old backups and save storage space)

Best Practices

8

Backup Best Practices

# ============================================================
# BEST PRACTICES FOR DATABASE BACKUPS
# ============================================================

print("1. BACKUP REGULARLY")
print("   - Daily backups are a minimum")
print("   - Critical systems may need hourly backups")

print("\n2. STORE BACKUPS IN MULTIPLE LOCATIONS")
print("   - Keep backups on different drives")
print("   - Consider cloud storage as a backup location")
print("   - Follow the 3-2-1 rule:")
print("      - 3 copies of your data")
print("      - 2 different media types")
print("      - 1 copy offsite")

print("\n3. TEST YOUR BACKUPS")
print("   - Regularly test restoring from backups")
print("   - Verify that backups are not corrupted")
print("   - Document the restore process")

print("\n4. USE COMPRESSION FOR LARGE DATABASES")
print("   - Save storage space")
print("   - Faster transfer to offsite locations")

print("\n5. ENCRYPT SENSITIVE BACKUPS")
print("   - Protect customer data")
print("   - Use encryption for compliance")

print("\n6. MONITOR BACKUP SUCCESS")
print("   - Set up alerts for failed backups")
print("   - Check backup logs regularly")

print("\n7. ROTATE BACKUPS")
print("   - Keep daily backups for 7 days")
print("   - Keep weekly backups for 30 days")
print("   - Keep monthly backups for 1 year")

print("\n8. DOCUMENT YOUR BACKUP STRATEGY")
print("   - What gets backed up")
print("   - How often")
print("   - Where backups are stored")
print("   - How to restore")

print("\n9. BACKUP BEFORE MAJOR CHANGES")
print("   - Before running migrations")
print("   - Before software updates")
print("   - Before data modifications")

print("\n10. USE TRANSACTIONS FOR CONSISTENCY")
print("    - Use --single-transaction with mysqldump")
print("    - Ensures a consistent snapshot")

Summary of best practices:

  • Backup regularly — daily is minimum
  • Store in multiple locations — follow the 3-2-1 rule
  • Test your backups — verify they work
  • Use compression — save storage space
  • Encrypt sensitive data — protect privacy
  • Monitor and alert — know when backups fail
  • Rotate backups — manage storage effectively

Quick Check: What is the 3-2-1 backup rule? (Answer: 3 copies of data, 2 different media types, 1 copy offsite)

Try It Yourself

Explore backup concepts in the editor below.

Loading Pyodide... 0%
Python Code Editor
========================================
DATABASE BACKUP - PRACTICE
========================================

1. CREATING BACKUPS
----------------------------------------

šŸ“¦ Backup 1 created: myapp_db (14 MB)
šŸ“¦ Backup 2 created: user_db (12 MB)
šŸ“¦ Backup 3 created: order_db (13 MB)
šŸ“¦ Backup 4 created: logs_db (13 MB)

šŸ“‹ Available Backups:
--------------------------------------------------
ID: 1 | myapp_db | 2024-01-15 10:30:00 | 14 MB | āœ…
ID: 2 | user_db | 2024-01-15 10:30:00 | 12 MB | āœ…
ID: 3 | order_db | 2024-01-15 10:30:00 | 13 MB | āœ…
ID: 4 | logs_db | 2024-01-15 10:30:00 | 13 MB | šŸ“‹ Structure only
--------------------------------------------------
Total: 4 backups

2. RESTORING A BACKUP
----------------------------------------

šŸ”„ Restoring backup 1: myapp_db
Size: 14 MB
Timestamp: 2024-01-15 10:30:00
āœ… Restore completed successfully!

3. CLEANING OLD BACKUPS
----------------------------------------

šŸ—‘ļø Cleaning backups older than 7 days
Removed 2 old backups
2 backups remaining

4. BACKUP STRATEGY CHECKLIST
----------------------------------------

āœ… Daily backups scheduled
āœ… Weekly full backups
āœ… Backups stored offsite
āœ… Backup compression enabled
āœ… Retention policy: 7 days daily, 30 days weekly
āœ… Backup verification tested
āœ… Alert system configured

A good backup strategy protects your data!
šŸ†

You've Got It!

You now know how to backup MySQL databases from Python. You understand mysqldump, automation, and best practices for data protection.

Quick Quiz

Test what you've learned:

1. What is the most commonly used MySQL backup tool?
2. What does the 3-2-1 backup rule mean?
3. How can you compress a mysqldump backup?
4. What should you do before restoring a database?
5. What is the purpose of backup retention policy?

Frequently Asked Questions

How often should I backup my database? ā–¼

For production applications, daily backups are the minimum. Critical systems may need hourly backups. The frequency depends on how much data you can afford to lose.

What is the difference between full and incremental backups? ā–¼

Full backup copies the entire database. Incremental backup copies only changes since the last backup. Incremental backups are faster but require a full backup to restore.

What is a common interview question about backups? ā–¼

Common questions include: "What is the 3-2-1 backup rule?" "How do you backup a MySQL database?" "What is the difference between mysqldump and file copy backup?" and "How would you automate backups?"

Where should I store backups? ā–¼

Store backups in multiple locations: on the server, on a different drive, and offsite (cloud storage or remote server). This protects against hardware failure and disasters.

How do I test if a backup works? ā–¼

The only way to really test a backup is to restore it to a test environment and verify the data. Regularly test your backups to ensure they're working correctly.

Where to Go From Here

Now that you know how to backup your database, check out these related topics:

Best Practices

Learn the best practices for MySQL in Python.

Learn More →

Parameterized Queries

Learn how to keep your database secure.

Learn More →

Error Handling

Learn how to handle database errors properly.

Learn More →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: Aggregation Functions Next: Best Practices →