A powerful, universal database migration tool supporting migrations between PostgreSQL, MySQL/MariaDB, and SQLite databases.
- Python 3.8+
- uv - Fast Python package installer and resolver
apt update && apt install -y build-essential# Linux/macOS
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or visit: https://github.com/astral-sh/uvsource $HOME/.local/bin/env- Clone the repository:
git clone https://github.com/PasarGuard/db-migratons.git
cd db-migratons- Make the migration script executable:
chmod +x migrate.sh- Install dependencies:
uv syncThat's it! Dependencies are managed via pyproject.toml and installed in a local virtual environment.
Use a YAML configuration file for cleaner, reusable, and more secure migrations.
cp config.example.yml config.yml
nano config.yml # or use your preferred editorExample config.yml:
source:
type: "mysql"
path: "backup.sql" # For SQL dumps or SQLite files
# url: "mysql://user:pass@host:3306/db" # For live database connections
target:
type: "postgres"
url: "postgresql+asyncpg://user:password@localhost:5432/mydb"
exclude_tables: # Optional
- admin_usage_logs
- user_usage_logs
- node_stats
table_order: # Optional - customize for your schema
- users # Tables with no foreign key dependencies first
- posts # Tables that reference users
- comments # Tables that reference posts and users
enum_defaults: # Optional - for enum-like string columns
status: "pending"
role: "user"uv run migrations/universal.py --config config.yml
# Or short form:
uv run migrations/universal.py -c config.ymlBenefits:
- ✅ Clean and readable
- ✅ Reusable for repeated migrations
Simply run the script without arguments:
./migrate.shThis will launch an interactive menu where you can:
- Select your source database type
- Configure your target database
- Review the migration summary
- Execute the migration
For quick one-off migrations:
./migrate.sh <source> --to <type> --db <target_url> [--exclude-tables <tables>]Migrate SQLite to PostgreSQL:
./migrate.sh pasarguard.db --to postgres --db postgresql+asyncpg://user:pass@localhost:5432/mydbMigrate MySQL dump to PostgreSQL:
./migrate.sh mysql_dump.sql --to postgres --db postgresql+asyncpg://admin:password@localhost:5432/pasarguardMigrate PostgreSQL to MySQL:
./migrate.sh postgresql://user:pass@host:5432/sourcedb --to mysql --db mysql+pymysql://user:pass@host:3306/targetdbExclude specific tables (for faster migration):
./migrate.sh dump.sql --to postgres --db postgresql+asyncpg://user:pass@localhost:5432/mydb --exclude-tables admin_usage_logs,user_usage_logs,node_statspostgresql+asyncpg://username:password@host:port/database
mysql+pymysql://username:password@host:port/database
sqlite:///path/to/database.db
# or simply: database.db
| From ↓ / To → | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| PostgreSQL | ➖ | ✅ | ✅ |
| MySQL | ✅ | ➖ | ✅ |
| SQLite | ✅ | ✅ | ➖ |
- Source Detection: Automatically detects source type (SQL dump or live database)
- Data Extraction: Parses SQL dumps or connects to live databases
- Schema Conversion: Converts data types and schema between database systems
- Target Preparation: Clears target database (with confirmation)
- Data Import: Imports data with type conversion and validation
- Progress Reporting: Shows detailed progress and error reporting
You can exclude specific tables from migration to speed up the process or skip unnecessary data like logs:
--exclude-tables "table1,table2,table3"Common tables to exclude:
admin_usage_logs- Admin activity logsuser_usage_logs- User activity logsnode_stats- Historical node statisticsnode_usages- Node usage historyuser_subscription_updates- Subscription update history
For custom database schemas, you can specify the order in which tables should be cleared and imported based on foreign key dependencies. This is crucial to avoid constraint violations during migration.
In your config file:
table_order:
- users # No foreign keys - import first
- categories # No foreign keys
- posts # References users - import after users
- tags # No foreign keys
- post_tags # References posts and tags - import last
- comments # References posts and usersOrdering rules:
- List tables with no foreign key dependencies first
- List tables that reference those tables next
- Continue in dependency order
- If not specified, the tool uses the default PasarGuard schema order
Why is this important?
- Tables are cleared in reverse order to avoid FK violations during deletion
- Tables are imported in specified order to satisfy FK constraints during insertion
- Wrong order will cause "foreign key constraint violation" errors
For columns with enum-like string values that are NOT NULL but may have NULL values in the source data, you can specify default values to use during migration.
In your config file:
enum_defaults:
status: "pending" # Default for 'status' column
role: "user" # Default for 'role' column
visibility: "public" # Default for 'visibility' columnBehavior:
- If not specified: Uses PasarGuard defaults (
fingerprint: "none",security: "inbound_default") - If set to
{}: Disables all enum defaults (uses empty strings forNOT NULLtext columns) - If specified: Uses your custom defaults
When is this useful?
- Migrating databases with enum-like string columns (e.g.,
status,role,type) - Handling
NULLvalues in source data forNOT NULLcolumns - Ensuring data consistency during migration with sensible defaults
The tool intelligently maps data types between databases:
| MySQL | PostgreSQL | SQLite |
|---|---|---|
| BIGINT | BIGINT | INTEGER |
| VARCHAR | VARCHAR | TEXT |
| DATETIME | TIMESTAMP | TEXT |
| JSON | JSONB | TEXT |
| ENUM | VARCHAR | TEXT |
| TINYINT(1) | BOOLEAN | INTEGER |
The repository includes example configuration files:
config.example.yml- Complete template with all options and commentsconfig.mysql-to-postgres.yml- MySQL → PostgreSQL migration exampleconfig.postgres-to-mysql.yml- PostgreSQL → MySQL migration example
source:
type: "mysql" # postgres, mysql, or sqlite
path: "backup.sql" # For SQL dumps or SQLite files
# OR
url: "mysql://..." # For live database connections
target:
type: "postgres" # postgres, mysql, or sqlite
url: "postgresql+asyncpg://..." # For live databases (recommended)
# OR
path: "output.db" # For SQLite output
exclude_tables: # Optional
- admin_usage_logs
- user_usage_logs
table_order: # Optional - for custom schemas
- users # Order tables by foreign key dependencies
- posts # Tables with no FKs first, dependent tables later
- comments
enum_defaults: # Optional - enum column defaults
status: "pending" # Default value for 'status' column
role: "user" # Default value for 'role' column- ✅ Interactive confirmation required
- ✅ Shows auto-increment columns that will be reset
- ✅ Preview migration summary before execution
- ✅ Password masking in output
- ✅ Detailed error reporting
- ✅ Transaction support with proper rollback
- ✅ Batch operations (1000 rows per commit) for performance
The project includes specialized migration scripts:
migrations/universal.py- Universal migrator for all database types (recommended)
uv not found:
curl -LsSf https://astral.sh/uv/install.sh | shConnection errors:
- Verify database credentials
- Check network connectivity
- Ensure database server is running
- Verify port numbers and hostnames
Permission errors:
chmod +x migrate.shType conversion errors:
- Check the migration output for specific errors
- Some complex types may need manual adjustment
- Review the data type mapping table above
The tool automatically manages these dependencies via uv:
sqlalchemy- Database toolkit and ORMasyncpg- PostgreSQL async driverpymysql- MySQL driverpyyaml- YAML configuration file parser
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
For issues, questions, or contributions, please visit: https://github.com/PasarGuard/db-migratons https://t.me/PasarGuardGP
- Built with SQLAlchemy
- Dependency management by uv
- Async PostgreSQL support via asyncpg
Made with ❤️ by PasarGuard