The key answer to how to handle races is how databases normally handle races, using a Transaction. If the program places the check and the creation of the tables and such in a transaction, you won't have the race problem. First, you don't first check if the DB exists, you just open it and see if the needed tables/data does (inside a transaction). If you use a simple BEGIN, then the second one might see the tables not there when it checks but will get a BUSY return when it goes to create the tables, and that tells it it needs to back off and start over. If you use a BEGIN IMMEDIATE, then the second one will delay doing its test due to the busy wait until the first finishes. This makes the logic simpler, but if the database in use might have longish write transactions might get some delays on start that wouldn't be otherwise needed.