diff --git a/cmd/certs.go b/cmd/certs.go
index 89521da..6603e55 100644
--- a/cmd/certs.go
+++ b/cmd/certs.go
@@ -35,7 +35,7 @@ func certs(ctx *cli.Context) error {
 				panic(err)
 			}
 		}
-		if err := keyDatabase.Sync(); err != nil {
+		if err := keyDatabase.Close(); err != nil {
 			panic(err)
 		}
 		os.Exit(0)
diff --git a/cmd/main.go b/cmd/main.go
index 222c295..7eb3fac 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -94,7 +94,7 @@ func Serve(ctx *cli.Context) error {
 	if err != nil {
 		return fmt.Errorf("could not create database: %v", err)
 	}
-	defer keyDatabase.Sync() //nolint:errcheck    // database has no close ... sync behave like it
+	defer keyDatabase.Close() //nolint:errcheck    // database has no close ... sync behave like it
 
 	listener = tls.NewListener(listener, certificates.TLSConfig(mainDomainSuffix,
 		giteaRoot, giteaAPIToken, dnsProvider,
diff --git a/server/certificates/certificates.go b/server/certificates/certificates.go
index b20f623..d2f7c76 100644
--- a/server/certificates/certificates.go
+++ b/server/certificates/certificates.go
@@ -38,7 +38,7 @@ func TLSConfig(mainDomainSuffix []byte,
 	giteaRoot, giteaApiToken, dnsProvider string,
 	acmeUseRateLimits bool,
 	keyCache, challengeCache, dnsLookupCache, canonicalDomainCache cache.SetGetKey,
-	keyDatabase database.KeyDB) *tls.Config {
+	keyDatabase database.CertDB) *tls.Config {
 	return &tls.Config{
 		// check DNS name & get certificate from Let's Encrypt
 		GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
@@ -185,7 +185,7 @@ func (a AcmeHTTPChallengeProvider) CleanUp(domain, token, _ string) error {
 	return nil
 }
 
-func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUseRateLimits bool, keyDatabase database.KeyDB) (tls.Certificate, bool) {
+func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUseRateLimits bool, keyDatabase database.CertDB) (tls.Certificate, bool) {
 	// parse certificate from database
 	res := &certificate.Resource{}
 	if !database.PogrebGet(keyDatabase, sni, res) {
@@ -229,7 +229,7 @@ func retrieveCertFromDB(sni, mainDomainSuffix []byte, dnsProvider string, acmeUs
 
 var obtainLocks = sync.Map{}
 
-func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Resource, user, dnsProvider string, mainDomainSuffix []byte, acmeUseRateLimits bool, keyDatabase database.KeyDB) (tls.Certificate, error) {
+func obtainCert(acmeClient *lego.Client, domains []string, renew *certificate.Resource, user, dnsProvider string, mainDomainSuffix []byte, acmeUseRateLimits bool, keyDatabase database.CertDB) (tls.Certificate, error) {
 	name := strings.TrimPrefix(domains[0], "*")
 	if dnsProvider == "" && len(domains[0]) > 0 && domains[0][0] == '*' {
 		domains = domains[1:]
@@ -392,7 +392,7 @@ func SetupAcmeConfig(acmeAPI, acmeMail, acmeEabHmac, acmeEabKID string, acmeAcce
 	return myAcmeConfig, nil
 }
 
-func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.KeyDB) {
+func SetupCertificates(mainDomainSuffix []byte, dnsProvider string, acmeConfig *lego.Config, acmeUseRateLimits, enableHTTPServer bool, challengeCache cache.SetGetKey, keyDatabase database.CertDB) {
 	// getting main cert before ACME account so that we can panic here on database failure without hitting rate limits
 	mainCertBytes, err := keyDatabase.Get(mainDomainSuffix)
 	if err != nil {
diff --git a/server/certificates/mock.go b/server/certificates/mock.go
index 19adb92..22d5470 100644
--- a/server/certificates/mock.go
+++ b/server/certificates/mock.go
@@ -17,7 +17,7 @@ import (
 	"codeberg.org/codeberg/pages/server/database"
 )
 
-func mockCert(domain, msg, mainDomainSuffix string, keyDatabase database.KeyDB) tls.Certificate {
+func mockCert(domain, msg, mainDomainSuffix string, keyDatabase database.CertDB) tls.Certificate {
 	key, err := certcrypto.GeneratePrivateKey(certcrypto.RSA2048)
 	if err != nil {
 		panic(err)
diff --git a/server/database/helpers.go b/server/database/helpers.go
index 98ea3fa..ea3e899 100644
--- a/server/database/helpers.go
+++ b/server/database/helpers.go
@@ -5,7 +5,7 @@ import (
 	"encoding/gob"
 )
 
-func PogrebPut(db KeyDB, name []byte, obj interface{}) {
+func PogrebPut(db CertDB, name []byte, obj interface{}) {
 	var resGob bytes.Buffer
 	resEnc := gob.NewEncoder(&resGob)
 	err := resEnc.Encode(obj)
@@ -18,7 +18,7 @@ func PogrebPut(db KeyDB, name []byte, obj interface{}) {
 	}
 }
 
-func PogrebGet(db KeyDB, name []byte, obj interface{}) bool {
+func PogrebGet(db CertDB, name []byte, obj interface{}) bool {
 	resBytes, err := db.Get(name)
 	if err != nil {
 		panic(err)
diff --git a/server/database/interface.go b/server/database/interface.go
index 2b582ae..80d74d3 100644
--- a/server/database/interface.go
+++ b/server/database/interface.go
@@ -2,8 +2,8 @@ package database
 
 import "github.com/akrylysov/pogreb"
 
-type KeyDB interface {
-	Sync() error
+type CertDB interface {
+	Close() error
 	Put(key []byte, value []byte) error
 	Get(key []byte) ([]byte, error)
 	Delete(key []byte) error
diff --git a/server/database/setup.go b/server/database/setup.go
index c16ff36..f7eeafc 100644
--- a/server/database/setup.go
+++ b/server/database/setup.go
@@ -1,19 +1,100 @@
 package database
 
 import (
+	"context"
 	"fmt"
+	"time"
+
+	"github.com/rs/zerolog/log"
+
 	"github.com/akrylysov/pogreb"
 	"github.com/akrylysov/pogreb/fs"
-	"time"
 )
 
-func New(path string) (KeyDB, error) {
+type aDB struct {
+	ctx          context.Context
+	cancel       context.CancelFunc
+	intern       *pogreb.DB
+	syncInterval time.Duration
+}
+
+func (p aDB) Close() error {
+	p.cancel()
+	return p.intern.Sync()
+}
+
+func (p aDB) Put(key []byte, value []byte) error {
+	return p.intern.Put(key, value)
+}
+
+func (p aDB) Get(key []byte) ([]byte, error) {
+	return p.intern.Get(key)
+}
+
+func (p aDB) Delete(key []byte) error {
+	return p.intern.Delete(key)
+}
+
+func (p aDB) Compact() (pogreb.CompactionResult, error) {
+	return p.intern.Compact()
+}
+
+func (p aDB) Items() *pogreb.ItemIterator {
+	return p.intern.Items()
+}
+
+var _ CertDB = &aDB{}
+
+func (p aDB) sync() {
+	for {
+		err := p.intern.Sync()
+		if err != nil {
+			log.Err(err).Msg("Syncing cert database failed")
+		}
+		select {
+		case <-p.ctx.Done():
+			return
+		case <-time.After(p.syncInterval):
+		}
+	}
+}
+
+func (p aDB) compact() {
+	for {
+		err := p.intern.Sync()
+		if err != nil {
+			log.Err(err).Msg("Syncing cert database failed")
+		}
+		select {
+		case <-p.ctx.Done():
+			return
+		case <-time.After(p.syncInterval):
+		}
+	}
+}
+
+func New(path string) (CertDB, error) {
 	if path == "" {
 		return nil, fmt.Errorf("path not set")
 	}
-	return pogreb.Open(path, &pogreb.Options{
+	db, err := pogreb.Open(path, &pogreb.Options{
 		BackgroundSyncInterval:       30 * time.Second,
 		BackgroundCompactionInterval: 6 * time.Hour,
 		FileSystem:                   fs.OSMMap,
 	})
+	if err != nil {
+		return nil, err
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	result := &aDB{
+		ctx:          ctx,
+		cancel:       cancel,
+		intern:       db,
+		syncInterval: 5 * time.Minute,
+	}
+
+	go result.sync()
+
+	return result, nil
 }