Skip to content

SQLITE_BUSY error on concurrent SELECT queries while in WAL mode

Scanning the result of multiple concurrent SELECT queries (eg. each in their own goroutine) results in the following error:

database is locked (5) (SQLITE_BUSY)

If I switch to the mattn/go-sqlite3 driver OR execute the queries in a single goroutine everything seems to work fine.

Here is a minimal reproducible example:

package main

import (
	"database/sql"
	"log"
	"sync"

	_ "github.com/mattn/go-sqlite3"
	_ "modernc.org/sqlite"
)

func main() {
	var wg sync.WaitGroup

	// mattn/go-sqlite3
	// ---
	// db, openErr := sql.Open("sqlite3", "data.db?_journal_mode=WAL")

	// modernc.org/sqlite
	// ---
	db, openErr := sql.Open("sqlite", "data.db?_pragma=journal_mode(WAL)")

	if openErr != nil {
		log.Fatal(openErr)
	}

	// run the queries
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()

			var id int

			row := db.QueryRow("SELECT 1")
			if err := row.Scan(&id); err != nil {
				log.Fatal(err)
			}
		}()
	}

	// wait the goroutines to complete
	wg.Wait()

	log.Println("Completed successfully!")
}

For context, this error was reported initially in https://github.com/pocketbase/pocketbase/issues/875.

edit1: simplified the example and left only the select statement edit2: fixed wg.Add placement

Edited by Gani Georgiev