SQLite Thread Locks vs MySQL Databases

Performance & Lag Reviewed September 6, 2026 3 min read

A plugin that logs every block break, every login, every economy transaction is writing constantly. Point it at a .db file instead of a real database server, and every one of those writes can end up queuing behind the main thread — which is a very roundabout way to lose TPS to a feature nobody would call performance-critical.

The mechanism

SQLite is not a server — it is a library that reads and writes a single flat file directly, with no separate process managing access. To keep that file consistent, SQLite's default mode allows one writer at a time: while a write is happening, every other connection wanting to write has to wait for it to finish, and by default even readers can be held up.

A plugin logging block changes, chat, or economy transactions writes constantly, and each one of those writes has to acquire that file lock. If the plugin's database calls happen on the main thread rather than a background one, that wait becomes a wait the entire game is doing — every player, every entity, frozen for the length of a disk write.

SQLite versus a MySQL server

SQLite (.db file)MySQL
What it isA library linked into the plugin, writing straight to a fileA separate server process, accessed over a connection
Concurrent writesOne at a time, file-lockedMany, with row-level locking in InnoDB
Where the wait happensWhichever thread issued the write — often the main threadThe plugin's own connection, which a well-written plugin keeps off the main thread
Good fit forA single-player tool, a low-traffic personal serverAny plugin logging more than the occasional event
The plugin does not have to be badly written for this to bite

Plenty of plugins that behave perfectly on MySQL default to SQLite because it needs no setup — and the same plugin, same settings, same server, can go from unnoticeable to a visible TPS drop the moment write volume increases, with nothing in the plugin's own code having changed at all. The database engine is the variable, not the plugin's quality.

Moving a plugin off SQLite

  1. Check the plugin's config for a storage or database section

    Almost every plugin capable of using MySQL exposes host, port, database name, username and password fields — usually commented out or set to SQLite by default.

  2. Point it at the MySQL database included with your plan

    Create one from the Databases tab if you have not, and use the local host address shown there rather than a public IP.

  3. Restart once, and confirm in the plugin's own startup log

    Most print a line confirming which engine they connected to. That line is the proof the switch took, not just that the config file changed.

How to confirm it worked

The plugin's log confirms a MySQL connection, and TPS stays steady during the activity that used to cause a dip — mass block breaking, a busy shop, a login wave.