Database & Migration
Since v3.0.0 all status is stored in MySQL via oxmysql instead of the old
database.json flat file. The in-memory state is the runtime source of truth and is
mirrored to MySQL so it survives restarts and relogs.
Table schema
Created automatically on first start — no manual .sql import needed.
CREATE TABLE IF NOT EXISTS `msk_handcuffs` (
`identifier` VARCHAR(64) NOT NULL,
`isCuffed` TINYINT(1) NOT NULL DEFAULT 0,
`cuffItem` VARCHAR(64) DEFAULT NULL,
`isAdminCuffed` TINYINT(1) NOT NULL DEFAULT 0,
`isHardcuffed` TINYINT(1) NOT NULL DEFAULT 0,
`hardcuffItem` VARCHAR(64) DEFAULT NULL,
`hasAnkleTracker` TINYINT(1) NOT NULL DEFAULT 0,
`hasHeadbag` TINYINT(1) NOT NULL DEFAULT 0,
`hasTape` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
identifier is the framework identifier from msk_core:
- ESX → license identifier (without the
license:prefix) - QBCore →
citizenid
Rows are removed automatically once a player has no active status left, keeping the table clean.
Automatic migration from database.json
If a legacy database.json exists on first start, msk_handcuffs imports it once:
- Each identifier that does not already exist in MySQL is inserted (non-destructive).
- The legacy key
ankleTrackeris normalized tohasAnkleTracker. - The original file is backed up to
database.migrated.bak.json. database.jsonis reset to{}so the migration never runs twice.
You will see a log line like:
[msk_handcuffs] Migrated 42 entries from database.json to MySQL (backup: database.migrated.bak.json).
The migration is idempotent and safe to leave in place. After a successful migration you
can delete database.json and database.migrated.bak.json if you no longer need the backup.
Reading status
Prefer statebags for live reads, or the exports for identifier/offline lookups. Direct SQL access is not required for integrations.