             schemaCache: SimpleDatabaseSchemaCache(),
             defaultLabel: "GRDB.DatabasePool",
             purpose: "writer")
+        
+        // Readers
+        readerConfiguration = configuration
+        readerConfiguration.readonly = true
+        // Readers use deferred transactions by default.
+        // Other transaction kinds are forbidden by SQLite in read-only connections.
+        readerConfiguration.defaultTransactionKind = .deferred
+        // Readers can't allow dangling transactions because there's no
+        // guarantee that one can get the same reader later in order to close
+        // an opened transaction.
+        readerConfiguration.allowsUnsafeTransactions = false
+        var readerCount = 0
+        readerPool = Pool(maximumCount: configuration.maximumReaderCount, makeElement: { [unowned self] in
+            readerCount += 1 // protected by pool (TODO: documented this protection behavior)
+            let reader = try SerializedDatabase(
+                path: path,
+                configuration: self.readerConfiguration,
+                schemaCache: SimpleDatabaseSchemaCache(),
+                defaultLabel: "GRDB.DatabasePool",
+                purpose: "reader.\(readerCount)")
+            reader.sync { self.setupDatabase($0) }
+            return reader
+        })
         
         // Activate WAL Mode unless readonly
         if !configuration.readonly {

        try readerPool.barrier {
            try writer.sync { try $0.changePassphrase(passphrase) }
            readerPool.removeAll()
            readerConfig._passphrase = passphrase
        }
    }
}

/// A DatabasePool grants concurrent accesses to an SQLite database.
public final class DatabasePool: DatabaseWriter {
    private let writer: SerializedDatabase
    private var readerPool: Pool<SerializedDatabase>!
    var readerConfiguration: Configuration
    
    private var functions = Set<DatabaseFunction>()
    private var collations = Set<DatabaseCollation>()
