diff --git a/storage/sql/config.go b/storage/sql/config.go
index bf56d017d140b0bf52e2aa776a3bf6860ffa6767..4bff016b526b76bdd6337d694cd877e5e8fdae60 100644
--- a/storage/sql/config.go
+++ b/storage/sql/config.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net/url"
 	"strconv"
+	"time"
 
 	"github.com/coreos/dex/storage"
 )
@@ -17,7 +18,11 @@ type SQLite3 struct {
 
 // Open creates a new storage implementation backed by SQLite3
 func (s *SQLite3) Open() (storage.Storage, error) {
-	return s.open()
+	conn, err := s.open()
+	if err != nil {
+		return nil, err
+	}
+	return withGC(conn, time.Now), nil
 }
 
 func (s *SQLite3) open() (*conn, error) {
@@ -67,7 +72,11 @@ type Postgres struct {
 
 // Open creates a new storage implementation backed by Postgres.
 func (p *Postgres) Open() (storage.Storage, error) {
-	return p.open()
+	conn, err := p.open()
+	if err != nil {
+		return nil, err
+	}
+	return withGC(conn, time.Now), nil
 }
 
 func (p *Postgres) open() (*conn, error) {
diff --git a/storage/sql/gc.go b/storage/sql/gc.go
index 11e70f95dc6471e1985c2a9fbbd9f3350bce73e9..1636c087e647a7194540cc7d4e4193404f384f86 100644
--- a/storage/sql/gc.go
+++ b/storage/sql/gc.go
@@ -1,8 +1,12 @@
 package sql
 
 import (
+	"context"
 	"fmt"
+	"log"
 	"time"
+
+	"github.com/coreos/dex/storage"
 )
 
 type gc struct {
@@ -10,10 +14,8 @@ type gc struct {
 	conn *conn
 }
 
-var tablesWithGC = []string{"auth_request", "auth_code"}
-
 func (gc gc) run() error {
-	for _, table := range tablesWithGC {
+	for _, table := range []string{"auth_request", "auth_code"} {
 		_, err := gc.conn.Exec(`delete from `+table+` where expiry < $1`, gc.now())
 		if err != nil {
 			return fmt.Errorf("gc %s: %v", table, err)
@@ -22,3 +24,30 @@ func (gc gc) run() error {
 	}
 	return nil
 }
+
+type withCancel struct {
+	storage.Storage
+	cancel context.CancelFunc
+}
+
+func (w withCancel) Close() error {
+	w.cancel()
+	return w.Storage.Close()
+}
+
+func withGC(conn *conn, now func() time.Time) storage.Storage {
+	ctx, cancel := context.WithCancel(context.Background())
+	run := (gc{now, conn}).run
+	go func() {
+		for {
+			select {
+			case <-time.After(time.Second * 30):
+				if err := run(); err != nil {
+					log.Printf("gc failed: %v", err)
+				}
+			case <-ctx.Done():
+			}
+		}
+	}()
+	return withCancel{conn, cancel}
+}