Usage¶
sqlite3mysql transfers SQLite 3 schema and data to MySQL or MariaDB. It
reads the source schema from SQLite, creates equivalent MySQL/MariaDB tables,
indexes, foreign keys, and views where possible, then transfers table data into
the target database.
Prerequisites¶
Python 3.9 or newer, unless you use the Docker image.
A readable SQLite 3 database file.
A reachable MySQL or MariaDB server.
A MySQL user that can connect, create the target database when it does not exist, create tables and views, insert data, add indexes, and add foreign keys.
See the GitHub Actions CI matrix for the current MySQL and MariaDB versions tested by the project. Very old server versions are more likely to differ in type, default-value, JSON, FULLTEXT, or authentication behavior.
Installation¶
Install from PyPI:
pip install sqlite3-to-mysql
sqlite3mysql --help
On macOS, you can also install with Homebrew:
brew install sqlite3-to-mysql
sqlite3mysql --help
Or run the published Docker image:
docker run --rm ghcr.io/techouse/sqlite3-to-mysql:latest --help
Quick start¶
Use -p / --prompt-mysql-password for interactive password entry. This
avoids putting the password in shell history or process listings.
sqlite3mysql \
--sqlite-file ./app.sqlite3 \
--mysql-database app_db \
--mysql-user app_user \
--prompt-mysql-password \
--mysql-host 127.0.0.1 \
--mysql-port 3306
Short options are equivalent:
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p -h 127.0.0.1 -P 3306
For automation, --mysql-password is available, but prefer a secret manager
or environment-expanded value rather than typing the password directly into your
shell history. The password is still passed as a command-line argument and may be
visible through process listings or logs.
Common recipes¶
Run with Docker¶
Use host.docker.internal when the MySQL or MariaDB server is running on the
host machine and the Docker container needs to reach it. On Linux Docker Engine,
add --add-host=host.docker.internal:host-gateway before the image name if
host.docker.internal is not resolvable.
docker run -it \
--rm \
--workdir "$PWD" \
--volume "$PWD:$PWD" \
ghcr.io/techouse/sqlite3-to-mysql:latest \
-f ./app.sqlite3 \
-d app_db \
-u app_user \
-p \
-h host.docker.internal
Files inside the mounted working directory are shared with the host.
Transfer schema only¶
Create the MySQL tables, indexes, views, and foreign keys without transferring table rows.
sqlite3mysql -f ./schema.sqlite3 -d app_db -u app_user -p --mysql-skip-transfer-data
Transfer data into existing MySQL tables¶
--mysql-skip-create-tables skips DDL creation and only inserts data. The
MySQL tables must already exist and be compatible with the SQLite source schema.
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --mysql-skip-create-tables
Transfer only some tables¶
Table names are space-separated and are consumed until the next CLI option.
sqlite3mysql -f ./subset.sqlite3 -d app_db -u app_user -p --sqlite-tables users orders invoices
Transfer everything except selected tables:
sqlite3mysql -f ./subset.sqlite3 -d app_db -u app_user -p --exclude-sqlite-tables audit_log temp_imports
Selecting or excluding tables disables foreign key transfer because the referenced tables may not be present.
Refresh existing target tables¶
--mysql-truncate-tables deletes rows from matching target tables before
inserting data.
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --mysql-truncate-tables
Use --mysql-insert-method UPDATE to update existing rows when inserts hit
duplicate keys.
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --mysql-insert-method UPDATE
Use a Unix socket¶
Use a socket instead of TCP when the MySQL server is local and configured for socket connections.
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --mysql-socket /var/run/mysqld/mysqld.sock
Use SSL certificates¶
Verify the server certificate with a CA file:
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --mysql-ssl-ca /path/to/ca.pem
Use a client certificate and key:
sqlite3mysql \
-f ./app.sqlite3 \
-d app_db \
-u app_user \
-p \
--mysql-ssl-ca /path/to/ca.pem \
--mysql-ssl-cert /path/to/client-cert.pem \
--mysql-ssl-key /path/to/client-key.pem
Use --skip-ssl only when you explicitly need to disable MySQL connection
encryption.
Tune large transfers and logs¶
Use --chunk to tune the number of SQLite rows read at a time. Use
--quiet to suppress progress output and --log-file to write logs to a
file.
sqlite3mysql -f ./app.sqlite3 -d app_db -u app_user -p --chunk 50000 --quiet --log-file transfer.log
Options at a glance¶
Option |
Purpose |
|---|---|
|
Source SQLite database file. Required. |
|
Target MySQL/MariaDB database name. Required. |
|
MySQL/MariaDB user. Required. |
|
Prompt for the MySQL password. Preferred for interactive use. |
|
Provide the MySQL password directly. Useful for automation, but handle carefully. |
|
MySQL host. Defaults to |
|
MySQL port. Defaults to |
|
MySQL Unix socket path. Cannot be combined with SSL certificate options. |
|
Transfer only the listed tables. Implies no foreign key transfer. |
|
Transfer every table except the listed tables. Implies no foreign key transfer. |
|
Materialize SQLite views as MySQL tables instead of creating MySQL views. |
|
Do not create foreign keys in MySQL. |
|
Skip duplicate SQLite index names instead of renaming them with a numeric suffix. |
|
Truncate matching target tables before inserting data. |
|
Skip table/view creation and transfer data only. |
|
Create schema only and skip table data. |
|
Choose duplicate-row insert behavior. Defaults to |
|
MySQL default integer column type. Defaults to |
|
MySQL default string column type. Defaults to |
|
MySQL default text column type. Defaults to |
|
MySQL database and table character set. Defaults to |
|
MySQL database and table collation. Must belong to the selected charset. |
|
Path to an SSL CA certificate file. |
|
Path to an SSL client certificate file. Must be paired with |
|
Path to an SSL client key file. Must be paired with |
|
Disable MySQL connection encryption. Cannot be used with SSL certificate options. |
|
Use FULLTEXT indexes on text columns when the target server supports InnoDB FULLTEXT. |
|
Transfer SQLite |
|
Read and write SQL records in batches. |
|
Write logs to a file. |
|
Show only errors after the initial command banner. |
|
Re-raise exceptions for debugging instead of printing friendly errors. |
|
Show environment and dependency versions. |
|
Show CLI help. |
Combinations and caveats¶
--sqlite-tablesand--exclude-sqlite-tablesare mutually exclusive.Either table filter (
--sqlite-tablesor--exclude-sqlite-tables) automatically disables foreign key transfer.--mysql-skip-create-tablesand--mysql-skip-transfer-datacannot be used together because there would be nothing to do.--mysql-skip-create-tablesrequires compatible target MySQL tables to already exist.--mysql-truncate-tablesdeletes rows from matching target tables before inserting data.--mysql-socketcannot be combined with--mysql-ssl-ca,--mysql-ssl-cert, or--mysql-ssl-key.--skip-sslcannot be combined with--mysql-ssl-ca,--mysql-ssl-cert, or--mysql-ssl-key.--mysql-ssl-certand--mysql-ssl-keymust be provided together.--mysql-collationmust be valid for the selected--mysql-charset.--use-fulltextfails before transfer starts when the target server does not support InnoDB FULLTEXT indexes.Native MySQL views are created by default. If a target table has the same name as a SQLite view, that target table is dropped before the MySQL view is created. Use
--sqlite-views-as-tablesfor the older materialized-table behavior.Table, view, column, index, and constraint names are truncated to MySQL’s 64-character identifier limit.
--mysql-passwordpasses the password as a command-line argument. Prefer--prompt-mysql-passwordfor interactive use and inject secrets through a secret manager or CI secret store for automation.
MySQL SSL note: when --mysql-ssl-ca is provided, MySQL Connector/Python
verifies the server certificate chain. --mysql-ssl-cert and
--mysql-ssl-key enable client certificate authentication. These options do
not enable hostname identity verification. If you provide only the client
certificate and key without --mysql-ssl-ca, the server certificate is not
verified.
MySQL, MariaDB, and SQLite notes¶
MySQL and MariaDB are similar but not identical. JSON behavior, expression defaults, duplicate-key update SQL, timestamp defaults, fractional seconds, and FULLTEXT support can differ by server family and version.
SQLite
JSONBmaps to MySQL/MariaDBJSONonly when the target supports JSON: MySQL>= 5.7.8and MariaDB>= 10.2.7. Otherwise it maps to the configured text type.SQLite
JSONBvalue conversion requires SQLite 3.45 or newer. With older SQLite versions, JSONB columns can still be selected, but the SQLitejson()conversion function is not used during transfer.--mysql-insert-method UPDATEuses the MySQLVALUES (...) AS __new__alias only on MySQL>= 8.0.19; MariaDB keeps the older duplicate-key update form.Expression defaults are supported on MySQL
>= 8.0.13and MariaDB>= 10.2.0; older servers may require defaults to be omitted or simplified.CURRENT_TIMESTAMPdefaults onDATETIMErequire MySQL>= 5.6.5or MariaDB>= 10.0.1.Fractional seconds require MySQL
>= 5.6.4or MariaDB>= 10.1.2.InnoDB FULLTEXT indexes require MySQL
>= 5.6.0or MariaDB>= 10.0.5.After transfer, verify schema details that are important to your application, especially defaults, collations, JSONB columns, views, and foreign keys.