Skip to main content

MySQL

MySQL

MySQL is a popular open-source relational database management system known for its reliability, ease of use, and performance.

Overview​

  • Versions: 8.4, 8.0, 5.7 (default: 8.4)
  • Default Port: 3306
  • Cluster Support: No (Single node only)
  • Use Cases: Relational data, web applications, OLTP workloads
  • Features: Backups, InnoDB engine

Key Features​

  • High Performance: Optimized for speed and efficiency
  • ACID Compliant: Full transaction support with InnoDB engine
  • Storage Engines: InnoDB, MyISAM, and others for different use cases
  • Rich Ecosystem: Extensive tooling and community support
  • Stored Procedures: Support for stored procedures, triggers, and views

Resources​

Choose the add-on's resources on the create form:

SettingOptionsDefault
CPU (vCPU)Any number of cores, e.g. 0.5, 1, 20.5
MemoryAny amount in GB, at least the type's minimum1 GB
DiskAny amount in GB10 GB
GPU Count0-8 (0 for CPU-only)0

Creating a MySQL Add-on​

  1. Navigate to Add-ons and click Create Add-on
  2. On the Create New Add-on page, select MySQL as the type
  3. Choose a version (8.4, 8.0, or 5.7)
  4. Configure:
    • Add-on Label (required): descriptive name (e.g., "app-database")
    • Description (optional): purpose and notes
    • Resources: CPU, memory, and disk for your workload
  5. Optionally enable automatic backups:
    • Schedule: Hourly, Daily, Weekly, or Monthly
    • Retention: number of backups to keep (1-30, default 7)
  6. Click Create Add-on

Connection Information​

Once the add-on is running, the Connection tab of the add-on details page shows the internal host (for apps), port, database, username, password, and a ready-to-use connection string. The same details are exposed to your apps via STRONGLY_SERVICES.

Connection String Format​

mysql://username:password@host:3306/defaultdb

The default database name is defaultdb. Credentials are auto-generated during add-on creation: the username is a randomly generated string (e.g., user_a1b2c3d4) and the password is a 32-character random secret.

Accessing Connection Details​

In STRONGLY_SERVICES, add-ons are grouped by type under services.addons, and each entry is one provisioned instance:

{
"id": "addon-abc123defg",
"name": "app-database",
"type": "mysql",
"category": "add-on",
"status": "running",
"version": "8.4",
"connection": {
"connection_string": "mysql://user_a1b2c3d4:<password>@<internal-host>:3306/defaultdb",
"uri": "mysql://user_a1b2c3d4:<password>@<internal-host>:3306/defaultdb",
"host": "<internal-host>",
"port": 3306,
"database": "defaultdb"
},
"auth": {
"method": "username_password",
"credentials": { "username": "user_a1b2c3d4", "password": "<password>" }
},
"limits": { "max_connections": 100, "storage_gb": 10 },
"metadata": { "cpu": "0.5", "memory": "1GB", "disk": "10GB", "backup_enabled": false }
}
import os
import json
import mysql.connector

# Parse STRONGLY_SERVICES
services = json.loads(os.environ['STRONGLY_SERVICES'])

# Pick your MySQL add-on by name (the label you gave it)
mysql_addon = next(
a for a in services['services']['addons']['mysql']
if a['name'] == 'app-database'
)

# Connect using individual parameters
conn = mysql.connector.connect(
host=mysql_addon['connection']['host'],
port=mysql_addon['connection']['port'],
database=mysql_addon['connection']['database'],
user=mysql_addon['auth']['credentials']['username'],
password=mysql_addon['auth']['credentials']['password']
)

cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE active = %s", (True,))
results = cursor.fetchall()

Common Operations​

Creating Tables​

CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
metadata JSON
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created ON users(created_at);

JSON Operations (MySQL 5.7+)​

-- Query JSON data
SELECT * FROM users
WHERE JSON_EXTRACT(metadata, '$.premium') = true;

-- Or using -> operator
SELECT * FROM users
WHERE metadata->>'$.premium' = 'true';

-- Update JSON field
UPDATE users
SET metadata = JSON_SET(metadata, '$.last_login', '2025-01-26')
WHERE id = 1;

-- Extract JSON field
SELECT email, metadata->>'$.plan' as plan
FROM users;
-- Create FULLTEXT index
ALTER TABLE articles ADD FULLTEXT INDEX idx_fulltext (title, content);

-- Search using MATCH AGAINST
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('mysql database' IN NATURAL LANGUAGE MODE);

-- Boolean search
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('+mysql -postgresql' IN BOOLEAN MODE);

Backups​

A MySQL backup is a mysqldump of all databases, with routines, events and triggers (backup.sql).

  • Back up now: click Backup Now on the status card, or Back Up Now on the Backup tab, while the add-on is running.

  • Automatic: on the Backup tab turn on Enable Automatic Backups, choose a Backup Schedule (Hourly, Daily, Weekly or Monthly) and a Retention (3, 7, 14 or 30 backups), and click Save Configuration. Older backups beyond the retention count are deleted automatically.

  • History: the Backup tab lists every backup with its status, size and any error.

  • Restore: click Restore next to a succeeded backup in Backup History and confirm. The backup is loaded back into this add-on while it keeps running: every database is dropped and recreated from the backup and the user accounts in it are reloaded. Queries fail until the restore finishes. Data written after the backup is lost. See Restoring a backup.

Performance Optimization​

Connection Pooling​

Use connection pooling for better performance:

from mysql.connector import pooling

# Create a connection pool
connection_pool = pooling.MySQLConnectionPool(
pool_name="mypool",
pool_size=10,
host='host',
database='database',
user='user',
password='password'
)

# Get connection from pool
conn = connection_pool.get_connection()
# Use connection
# ...
conn.close() # Returns to pool

Indexing Strategy​

-- Standard B-tree index
CREATE INDEX idx_users_email ON users(email);

-- Composite index
CREATE INDEX idx_users_email_active ON users(email, active);

-- Unique index
CREATE UNIQUE INDEX idx_users_username ON users(username);

-- Analyze index usage
SHOW INDEX FROM users;

-- Check index cardinality
SELECT table_name, index_name, cardinality
FROM information_schema.statistics
WHERE table_schema = 'your_database'
ORDER BY cardinality DESC;

Query Optimization​

-- Use EXPLAIN to analyze queries
EXPLAIN SELECT * FROM users WHERE email = 'user@example.com';

-- Analyze table for better statistics
ANALYZE TABLE users;

-- Optimize table (defragment and update statistics)
OPTIMIZE TABLE users;

-- See what your connections are running now
SHOW PROCESSLIST;

Monitoring​

The Metrics tab on the add-on details page measures the running add-on live: CPU, memory and disk use against its size, network traffic, open and new connections, response time, and instance health and uptime. See Metrics. The Logs tab shows its recent log output.

The add-on user has full rights on the defaultdb database but not server-wide administration, so server settings such as the slow query log (SET GLOBAL ...) cannot be changed. Use EXPLAIN and SHOW PROCESSLIST to find slow queries.

Best Practices​

  1. Use InnoDB Engine: Default engine with ACID compliance and row-level locking
  2. Enable Connection Pooling: Reduce connection overhead
  3. Regular Optimization: Run OPTIMIZE TABLE periodically
  4. Monitor Query Performance: Use EXPLAIN for slow queries
  5. Use Transactions: Wrap related operations in transactions
  6. Backup Regularly: Enable daily backups for production databases
  7. Use Prepared Statements: Prevent SQL injection and improve performance
  8. UTF8MB4 Charset: Use utf8mb4 for full Unicode support including emojis
  9. Avoid MyISAM: Use InnoDB for better reliability and performance

Migration Guide​

From PostgreSQL to MySQL​

Key differences to note:

-- PostgreSQL: SERIAL
-- MySQL: AUTO_INCREMENT
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY
);

-- PostgreSQL: LIMIT count OFFSET offset
-- MySQL: LIMIT offset, count (or LIMIT count OFFSET offset in newer versions)
SELECT * FROM users LIMIT 20, 10;
-- or
SELECT * FROM users LIMIT 10 OFFSET 20;

-- PostgreSQL: || operator
-- MySQL: CONCAT() function
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;

-- PostgreSQL: BOOLEAN type
-- MySQL: TINYINT(1) or BOOLEAN (alias for TINYINT(1))
CREATE TABLE users (
active BOOLEAN DEFAULT TRUE
);

-- PostgreSQL: NOW()
-- MySQL: NOW() or CURRENT_TIMESTAMP
SELECT NOW();

Troubleshooting​

Connection Issues​

# Test connection
mysql -h host -P 3306 -u username -p database

# Check connection limits
SHOW VARIABLES LIKE 'max_connections';

# View current connections
SHOW PROCESSLIST;

# Count connections by user
SELECT user, COUNT(*) FROM information_schema.processlist GROUP BY user;

Performance Issues​

-- Find long-running queries
SELECT id, user, host, db, command, time, state, info
FROM information_schema.processlist
WHERE command != 'Sleep' AND time > 5
ORDER BY time DESC;

-- Kill a long-running query
KILL QUERY process_id;

-- Check table sizes
SELECT table_schema, table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb
FROM information_schema.tables
WHERE table_schema = 'your_database'
ORDER BY (data_length + index_length) DESC;

Disk Space Issues​

-- Check database size
SELECT table_schema AS 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
FROM information_schema.tables
GROUP BY table_schema;

-- Check table sizes in current database
SELECT table_name,
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb,
ROUND((data_free / 1024 / 1024), 2) AS free_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY (data_length + index_length) DESC
LIMIT 10;

Support​

For issues or questions:

  • Check add-on logs in the Logs tab of the add-on details page
  • Review MySQL official documentation
  • Contact Strongly support through the platform