Try FFxF: $10 free with code TRY10, no credit card needed

API

Managed databases

Managed PostgreSQL, MySQL, MariaDB and Valkey in your private network: TLS connections, users, point-in-time restore, forks, public access.

A managed database is PostgreSQL, MySQL (Percona Server), MariaDB or Valkey (Redis-compatible) run by FFxF in one of your private networks: backed up continuously, restorable to any minute of the last 7 days, updated in a window you choose, with a publicly trusted certificate. You get a connection string; FFxF keeps the engine, the system and the backups running. Managed databases are in beta, open to every account.

Create a database

bash
curl -s https://api.ffxf.net/v1/databases/options -H "Authorization: Bearer $FFXF_TOKEN"

curl -s -X POST https://api.ffxf.net/v1/databases \
     -H "Authorization: Bearer $FFXF_TOKEN" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"name": "orders", "vpc": 12, "size_gb": 1}'
json
{ "data": { "id": 7, "name": "orders", "status": "pending", "engine": "postgresql", "version": "18", "region": "montreal", "size_gb": 1,
  "connection": { "host": "private-k3v9x2m1qa.db.ffxf.cloud", "port": 5432, "database": "defaultdb", "username": "ffxfadmin", "ssl_mode": "verify-full" } } }

"engine" picks postgresql (the default), mysql, mariadb or valkey; GET /databases/options lists their versions, the sizes with their hourly price (the same for every engine), and the extensions. Billing starts now, by the hour, like a machine: the account needs 24 hours of credit. The database is ready within a few minutes, when status goes from pending to active. It comes with an admin user, ffxfadmin, and a logical database, defaultdb (Valkey: the admin default, and no logical database).

Engines

EngineVersionsPortTLS, as the client sets it
PostgreSQL18, 175432sslmode=verify-full&sslrootcert=system
MySQL (Percona Server)8.43306--ssl-mode=VERIFY_IDENTITY
MariaDB11.83306--ssl-verify-server-cert
Valkey (Redis-compatible)8.16379rediss://, or --tls for valkey-cli and redis-cli

Every engine gets the same backups, forks, public access, maintenance window and disk. Backups differ for Valkey (hourly snapshots, see below); users and logical databases differ for MySQL, MariaDB and Valkey.

Connect

bash
curl -s https://api.ffxf.net/v1/databases/7/credentials -H "Authorization: Bearer $FFXF_TOKEN"
json
{ "data": { "users": [ { "username": "ffxfadmin", "admin": true, "password": "…", "connection_uri": "postgresql://ffxfadmin:…@private-k3v9x2m1qa.db.ffxf.cloud:5432/defaultdb?sslmode=verify-full&sslrootcert=system" } ],
  "connection_uri": "postgresql://ffxfadmin:…@private-k3v9x2m1qa.db.ffxf.cloud:5432/defaultdb?sslmode=verify-full&sslrootcert=system",
  "public_connection_uri": null } }

Machines of the private network reach the database at connection.host, on the engine's port. TLS is always required, with a Let's Encrypt certificate renewed for you: sslmode=verify-full checks both the certificate and the name. sslrootcert=system needs libpq 16 or later; with an older client, point sslrootcert at the system bundle (/etc/ssl/certs/ca-certificates.crt on Debian and Ubuntu).

bash
mysql --host=private-k3v9x2m1qa.db.ffxf.cloud --user=ffxfadmin -p --ssl-mode=VERIFY_IDENTITY defaultdb

valkey-cli -u "rediss://default:$VALKEY_PASSWORD@private-k3v9x2m1qa.db.ffxf.cloud:6379" PING

Passwords only come out of GET …/credentials and of the calls that create one, under the databases.write scope: a monitoring key with vms.read sees the database but cannot log in. Give the connection string to your application through an environment variable or a secret store, never in code.

Users, databases and extensions

bash
curl -s -X POST https://api.ffxf.net/v1/databases/7/users \
     -H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
     -d '{"username": "app"}'

curl -s -X POST https://api.ffxf.net/v1/databases/7/databases/defaultdb/extensions \
     -H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
     -d '{"extension": "vector"}'

A new user gets a generated password, returned once by the call (and readable later with …/credentials); it is live within seconds. Names are lowercase letters, digits and _; up to 30 users and 30 logical databases. The admin is not a superuser, but owns the logical databases. On PostgreSQL 15 and later, a new user cannot create tables in the public schema until the admin allows it:

sql
GRANT CREATE ON SCHEMA public TO app;

Extensions come from a list: vector (pgvector), postgis, pg_trgm, pgcrypto, uuid-ossp, hstore, citext, unaccent, ltree and a few more, all listed by GET /databases/options. Removing one does not cascade: if objects still depend on it, it stays, and the database's warning says why.

MySQL and MariaDB

Users and logical databases are created through the API or the console, not in SQL. Every user has all rights in every logical database, and the admin can pass them on (GRANT). The admin has no SUPER, FILE or CREATE USER, and no rights on the mysql schema. There are no extensions. Slow queries come from performance_schema, values replaced by ?, without the user.

Valkey

The admin is default: a client that only sends a password (AUTH <password>, rediss://:<password>@…) connects as it. Other users are ACL users: every key, every channel and every data command, including KEYS, FLUSHALL, SORT, INFO and CONFIG GET. Server commands (CONFIG SET, ACL, SAVE, SHUTDOWN, MODULE, MONITOR…) are refused. There is nothing to create for databases: the 16 numbered ones (SELECT 0 to 15) are open to every user.

bash
curl -s -X PATCH https://api.ffxf.net/v1/databases/9 \
     -H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
     -d '{"eviction_policy": "allkeys-lru"}'

About 60 % of the size holds the data (data_memory.max_bytes); the rest runs the system and the snapshots. eviction_policy says what happens when it is full: noeviction, the default, refuses writes and keeps everything; allkeys-lru removes the least used keys, for a cache; the volatile-* policies only remove keys that expire. Every write reaches the disk within a second. Off-site, a snapshot is taken every hour when there were writes: all are kept 24 hours, then one a day for 7 days. A restore brings back the last snapshot taken before the chosen minute. The slow queries are the commands with the most total time since the engine started, and statistics count commands rather than commits.

Backups and restore

Backups are automatic and included: a full backup every week, a differential every day, and the transaction log archived continuously. They are encrypted before they leave the database and kept 7 days, outside the server that runs it. Every week, the latest full backup is restored as a test and checked (backups.last_restore_test).

bash
curl -s -X POST https://api.ffxf.net/v1/databases/7/restore \
     -H "Authorization: Bearer $FFXF_TOKEN" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"at": "2026-10-14T09:30:00Z", "name": "orders-before-migration"}'

A restore never overwrites: it creates a new database, billed like any other, holding the data as it was at that minute, with the same users and passwords. Any minute of backups.restore_window works (GET …/backups). A deleted database keeps its backups 7 days, so it can still be restored that way. Before a risky migration, POST …/backups starts a backup on the spot.

Forks

bash
curl -s -X POST https://api.ffxf.net/v1/databases/7/forks \
     -H "Authorization: Bearer $FFXF_TOKEN" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"name": "orders-staging"}'

A fork is a new database whose data is an instant copy of the source, whatever its size: a staging copy, a test of a migration, an analysis that must not load production. It starts linked to its source: no backups of its own, and the source cannot be deleted. After 7 days, or with POST …/detach, it gets its own copy of the data (about 30 seconds of downtime) and its backups start.

Change size

bash
curl -s -X POST https://api.ffxf.net/v1/databases/7/resize \
     -H "Authorization: Bearer $FFXF_TOKEN" \
     -H "Idempotency-Key: $(uuidgen)" \
     -H "Content-Type: application/json" \
     -d '{"size_gb": 2}'

Moves the database to a larger size from GET /databases/options: more vCPU, memory and included disk. Data, users, names and addresses stay the same. The database restarts: one to two minutes of downtime, during which status is maintenance and resize.to_gb the size asked for; then it is active with its new size_gb. Engine settings that depend on memory (PostgreSQL buffers, the InnoDB buffer pool, Valkey data memory) follow. The new rate applies from the next hour. Larger sizes only: the disk does not shrink. Also in the console, under Settings.

Public access

bash
curl -s -X PUT https://api.ffxf.net/v1/databases/7/public-access \
     -H "Authorization: Bearer $FFXF_TOKEN" -H "Content-Type: application/json" \
     -d '{"enabled": true, "sources": ["203.0.113.10", "2001:db8::/48"]}'

Off at creation. Once on, the database also answers at public_access.host on its own port (kept for its whole life), over IPv4 and IPv6, TLS and password still required. sources restricts who may connect; omitted it is left as is, null or empty lets everyone in. Changes apply within about 30 seconds. Prefer the private network whenever the client runs at FFxF.

Day to day

ActionCallGood to know
StatisticsGET /databases/{id}/metrics?range=24hCPU, memory, connections and commits per minute; 1h, 24h or 7d, kept 7 days.
Slow queriesGET /databases/{id}/queriesThe 20 queries with the most total time, normalized ($1, $2… or ?); on Valkey, per command.
Eviction (Valkey)PATCH /databases/{id} with eviction_policyApplied within seconds; noeviction by default.
Maintenance windowPATCH /databases/{id} with maintenance_day and maintenance_hourSunday 3 a.m. Montréal time by default, 2 hours. Minor updates are applied then, usually with a minute or two of downtime.
DiskPATCH /databases/{id} with disk_cap_gbThe disk grows by itself at 80 % full, up to the cap. At the cap, an e-mail warns you; nearly full, the database turns read-only until the cap is raised or data deleted.
SizePOST /databases/{id}/resize with size_gbLarger sizes only; one to two minutes of downtime, new rate from the next hour.
DeleteDELETE /databases/{id}Billing stops; the backups stay 7 days. Refused while a linked fork depends on it.

Limits and billing

Three databases per account by default, more on request from the console. A database is billed by the hour according to its size; disk beyond what the size includes costs 0.15 CAD per GB per month, billed by the hour too. Backups, restores, the weekly restore test and public access are included.

Useful details

Reading needs vms.read (no passwords); creating, restoring, forking and resizing need vms.create and an Idempotency-Key; deleting needs vms.destroy; detaching a fork needs vms.action; a backup on demand needs backups.write; public access needs network.write. Passwords, users, logical databases, extensions and settings need databases.write. The MCP server exposes the same actions: see MCP tools.

Support & discussions

Technical questions, incident reports, or infrastructure discussions, the team is reachable on Discord, Telegram, X, Instagram, Reddit, and IRC.