diff --git a/api/v1alpha1/fields.go b/api/v1alpha1/fields.go
index 9cd8e08..bc800a0 100644
--- a/api/v1alpha1/fields.go
+++ b/api/v1alpha1/fields.go
@@ -1,5 +1,7 @@
 package v1alpha1
 
+type OwnerID string
+
 type SqlCredentials struct {
 	// Username for the sql user
 	Username string `json:"username,omitempty"`
diff --git a/api/v1alpha1/sqldatabase_types.go b/api/v1alpha1/sqldatabase_types.go
index d57d610..12ab2de 100644
--- a/api/v1alpha1/sqldatabase_types.go
+++ b/api/v1alpha1/sqldatabase_types.go
@@ -46,6 +46,9 @@ type SqlDatabaseStatus struct {
 
 	// Timestamp when the user was last updated/checked.
 	LastModifiedTimestamp *metav1.Time `json:"lastModifiedTimestamp,omitempty"`
+
+	// String used to identify owership
+	OwnerID OwnerID `json:"ownerID,omitempty"`
 }
 
 //+kubebuilder:object:root=true
diff --git a/api/v1alpha1/sqlgrants_types.go b/api/v1alpha1/sqlgrants_types.go
index a5f590e..d6f42ea 100644
--- a/api/v1alpha1/sqlgrants_types.go
+++ b/api/v1alpha1/sqlgrants_types.go
@@ -51,6 +51,9 @@ type SqlGrantStatus struct {
 	LastModifiedTimestamp *metav1.Time `json:"lastModifiedTimestamp,omitempty"`
 
 	CurrentGrants []string `json:"currentGrants,omitempty"`
+
+	// String used to identify owership
+	OwnerID OwnerID `json:"ownerID,omitempty"`
 }
 
 //+kubebuilder:object:root=true
diff --git a/api/v1alpha1/sqluser_types.go b/api/v1alpha1/sqluser_types.go
index dbbfd99..907011c 100644
--- a/api/v1alpha1/sqluser_types.go
+++ b/api/v1alpha1/sqluser_types.go
@@ -46,6 +46,9 @@ type SqlUserStatus struct {
 
 	// Timestamp when the user was last updated/checked.
 	LastModifiedTimestamp *metav1.Time `json:"lastModifiedTimestamp,omitempty"`
+
+	// String used to identify owership
+	OwnerID OwnerID `json:"ownerID,omitempty"`
 }
 
 //+kubebuilder:object:root=true
diff --git a/charts/sql-operator/crds/crds.yaml b/charts/sql-operator/crds/crds.yaml
index 11c5211..3b3ee02 100644
--- a/charts/sql-operator/crds/crds.yaml
+++ b/charts/sql-operator/crds/crds.yaml
@@ -90,6 +90,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
@@ -204,6 +207,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
@@ -363,6 +369,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
diff --git a/config/crd/bases/stenic.io_sqldatabases.yaml b/config/crd/bases/stenic.io_sqldatabases.yaml
index 91fca25..94078d7 100644
--- a/config/crd/bases/stenic.io_sqldatabases.yaml
+++ b/config/crd/bases/stenic.io_sqldatabases.yaml
@@ -77,6 +77,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
diff --git a/config/crd/bases/stenic.io_sqlgrants.yaml b/config/crd/bases/stenic.io_sqlgrants.yaml
index 736c30b..d551365 100644
--- a/config/crd/bases/stenic.io_sqlgrants.yaml
+++ b/config/crd/bases/stenic.io_sqlgrants.yaml
@@ -98,6 +98,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
diff --git a/config/crd/bases/stenic.io_sqlusers.yaml b/config/crd/bases/stenic.io_sqlusers.yaml
index acf7055..6ccea63 100644
--- a/config/crd/bases/stenic.io_sqlusers.yaml
+++ b/config/crd/bases/stenic.io_sqlusers.yaml
@@ -83,6 +83,9 @@ spec:
                 description: Timestamp when the user was last updated/checked.
                 format: date-time
                 type: string
+              ownerID:
+                description: String used to identify owership
+                type: string
             required:
             - created
             type: object
diff --git a/controllers/owner.go b/controllers/owner.go
new file mode 100644
index 0000000..6f2e49c
--- /dev/null
+++ b/controllers/owner.go
@@ -0,0 +1,36 @@
+package controllers
+
+import (
+	"context"
+	"fmt"
+
+	steniciov1alpha1 "github.com/stenic/sql-operator/api/v1alpha1"
+	"github.com/stenic/sql-operator/drivers"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func checkOwner(ctx context.Context, driver drivers.Driver, ownerShipData drivers.OwnerShipData, obj client.Object) (steniciov1alpha1.OwnerID, error) {
+	ownerState, err := driver.GetOwnerState(ctx, ownerShipData)
+	switch ownerState {
+	case drivers.NonExisting:
+		ownerShipData.OwnerID = steniciov1alpha1.OwnerID(obj.GetUID())
+		if err := driver.SetOwnerState(ctx, ownerShipData); err != nil {
+			return "", fmt.Errorf("failed to claim ownership - %s", err.Error())
+		}
+		return ownerShipData.OwnerID, nil
+	case drivers.NotOwner:
+		// We are not managing this resource)
+		return "", fmt.Errorf("resource already exists and will not managed by this sqlOperator")
+	case drivers.IsOwner:
+		// All good, proceed
+		break
+	default:
+		return "", fmt.Errorf("unknown ownerState '%s'", ownerState)
+	}
+
+	return "", err
+}
+
+func cleanupOwner(ctx context.Context, driver drivers.Driver, ownerShipData drivers.OwnerShipData) error {
+	return driver.DeleteOwnerState(ctx, ownerShipData)
+}
diff --git a/controllers/sqldatabase_controller.go b/controllers/sqldatabase_controller.go
index 83970ce..5048307 100644
--- a/controllers/sqldatabase_controller.go
+++ b/controllers/sqldatabase_controller.go
@@ -85,6 +85,18 @@ func (r *SqlDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 		return ctrl.Result{}, err
 	}
 
+	// Provide ownership data
+	err = driver.SetOwnershipData(ctx, drivers.OwnerShipData{
+		Type:     drivers.OwnerShipTypeDatabase,
+		Name:     database.Spec.DatabaseName,
+		Resource: req.NamespacedName.String(),
+		OwnerID:  database.Status.OwnerID,
+	})
+	if err != nil {
+		r.Recorder.Event(&host, "Warning", "Error", err.Error())
+		return ctrl.Result{RequeueAfter: r.RefreshRate * 2}, err
+	}
+
 	scheduledResult := ctrl.Result{RequeueAfter: r.RefreshRate}
 
 	finalizerName := "stenic.io/sqldatabase-deletion"
@@ -113,7 +125,7 @@ func (r *SqlDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 			if len(children.Items) > 0 {
 				err := fmt.Errorf(
 					"%s - [%s/%s] ...",
-					"Can't delete, found other referencing this object",
+					"can't delete, found other referencing this object",
 					children.Items[0].Namespace,
 					children.Items[0].Name,
 				)
@@ -122,15 +134,22 @@ func (r *SqlDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 				// might have been faster than referenced object, reschedule.
 				return scheduledResult, err
 			}
+			r.Recorder.Event(&database, "Normal", "Delete", "Validated no child objects")
 
-			if database.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
-				// delete the user
-				if err = driver.DeleteDatabase(ctx, database); err != nil {
-					r.Recorder.Event(&database, "Warning", "Error", err.Error())
-					sqlOperatorActionsFailures.With(promLabels).Inc()
-					return ctrl.Result{}, err
-				}
+			// Cleanup ref
+			if err := driver.DeleteOwnerState(ctx); err != nil {
+				log.Error(err, "unable to cleanup ownership")
+				return ctrl.Result{}, err
 			}
+			r.Recorder.Event(&database, "Normal", "Delete", "Removed owner references")
+
+			// delete the user
+			if err = driver.DeleteDatabase(ctx, database); err != nil {
+				r.Recorder.Event(&database, "Warning", "Error", err.Error())
+				sqlOperatorActionsFailures.With(promLabels).Inc()
+				return ctrl.Result{}, err
+			}
+			r.Recorder.Event(&database, "Normal", "Delete", "Deleted mysql object")
 
 			// remove our finalizer from the list and update it.
 			controllerutil.RemoveFinalizer(&database, finalizerName)
@@ -143,20 +162,14 @@ func (r *SqlDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 		return ctrl.Result{}, nil
 	}
 
-	// Deduplicate control loop
-	if database.Status.LastModifiedTimestamp != nil && time.Since(database.Status.LastModifiedTimestamp.Time) < r.RefreshRate {
+	if driver.Noop {
+		r.Recorder.Event(&database, "Normal", "Noop", "Determined object is not owned")
 		return ctrl.Result{}, nil
 	}
 
-	if !database.Status.Created {
-		database.Status.Created = true
-		database.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
-	}
-	database.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
-
-	if err := r.Status().Update(ctx, &database); err != nil {
-		log.Error(err, "unable to update SqlDatabase status")
-		return ctrl.Result{}, err
+	// Deduplicate control loop
+	if database.Status.LastModifiedTimestamp != nil && time.Since(database.Status.LastModifiedTimestamp.Time) < r.RefreshRate {
+		return ctrl.Result{}, nil
 	}
 
 	count, err := driver.UpsertDatabase(ctx, database)
@@ -169,6 +182,18 @@ func (r *SqlDatabaseReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	if count > 0 {
 		r.Recorder.Event(&database, "Normal", "Changed", fmt.Sprintf("%d queries executed", count))
 		sqlOperatorQueries.With(promLabels).Add(float64(count))
+
+		if !database.Status.Created {
+			database.Status.Created = true
+			database.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
+		}
+		database.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
+		database.Status.OwnerID = driver.GetOwnerID()
+
+		if err := r.Status().Update(ctx, &database); err != nil {
+			log.Error(err, "unable to update SqlDatabase status")
+			return ctrl.Result{}, err
+		}
 	}
 
 	return scheduledResult, nil
diff --git a/controllers/sqlgrants_controller.go b/controllers/sqlgrants_controller.go
index f7a68d4..70f2c94 100644
--- a/controllers/sqlgrants_controller.go
+++ b/controllers/sqlgrants_controller.go
@@ -105,6 +105,18 @@ func (r *SqlGrantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, err
 	}
 
+	// Provide ownership data
+	err = driver.SetOwnershipData(ctx, drivers.OwnerShipData{
+		Type:     drivers.OwnerShipTypeGrant,
+		Name:     grants.Name,
+		Resource: req.NamespacedName.String(),
+		OwnerID:  grants.Status.OwnerID,
+	})
+	if err != nil {
+		r.Recorder.Event(&host, "Warning", "Error", err.Error())
+		return ctrl.Result{RequeueAfter: r.RefreshRate * 2}, err
+	}
+
 	finalizerName := "stenic.io/sqlgrants-deletion"
 	// examine DeletionTimestamp to determine if object is under deletion
 	if grants.ObjectMeta.DeletionTimestamp.IsZero() {
@@ -122,14 +134,20 @@ func (r *SqlGrantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		if controllerutil.ContainsFinalizer(&grants, finalizerName) {
 			// our finalizer is present, so lets handle any external dependency
 
-			if grants.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
-				// delete the user
-				if err = driver.DeleteGrants(ctx, grants, user, database); err != nil {
-					r.Recorder.Event(&grants, "Warning", "Error", err.Error())
-					sqlOperatorActionsFailures.With(promLabels).Inc()
-					return ctrl.Result{}, err
-				}
+			// Cleanup ref
+			if err := driver.DeleteOwnerState(ctx); err != nil {
+				log.Error(err, "unable to cleanup ownership")
+				return ctrl.Result{}, err
+			}
+			r.Recorder.Event(&grants, "Normal", "Delete", "Removed owner references")
+
+			// delete the grant
+			if err = driver.DeleteGrants(ctx, grants, user, database); err != nil {
+				r.Recorder.Event(&grants, "Warning", "Error", err.Error())
+				sqlOperatorActionsFailures.With(promLabels).Inc()
+				return ctrl.Result{}, err
 			}
+			r.Recorder.Event(&grants, "Normal", "Delete", "Deleted mysql object")
 
 			// remove our finalizer from the list and update it.
 			controllerutil.RemoveFinalizer(&grants, finalizerName)
@@ -142,6 +160,11 @@ func (r *SqlGrantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		return ctrl.Result{}, nil
 	}
 
+	if driver.Noop {
+		r.Recorder.Event(&grants, "Normal", "Noop", "Determined object is not owned")
+		return ctrl.Result{}, nil
+	}
+
 	// Deduplicate control loop
 	if grants.Status.LastModifiedTimestamp != nil && time.Since(grants.Status.LastModifiedTimestamp.Time) < r.RefreshRate {
 		return ctrl.Result{}, nil
@@ -151,12 +174,6 @@ func (r *SqlGrantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 		grants.Status.CurrentGrants = []string{}
 	}
 
-	if !grants.Status.Created {
-		grants.Status.Created = true
-		grants.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
-	}
-	grants.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
-
 	if err := r.Status().Update(ctx, &grants); err != nil {
 		log.Error(err, "unable to update SqlGrant status")
 		return ctrl.Result{}, err
@@ -172,12 +189,18 @@ func (r *SqlGrantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c
 	if count > 0 {
 		r.Recorder.Event(&grants, "Normal", "Changed", fmt.Sprintf("%d queries executed", count))
 		sqlOperatorQueries.With(promLabels).Add(float64(count))
-	}
 
-	grants.Status.CurrentGrants = grants.Spec.Grants
-	if err := r.Status().Update(ctx, &grants); err != nil {
-		log.Error(err, "unable to update SqlGrant status")
-		return ctrl.Result{}, err
+		if !grants.Status.Created {
+			grants.Status.Created = true
+			grants.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
+		}
+		grants.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
+		grants.Status.CurrentGrants = grants.Spec.Grants
+
+		if err := r.Status().Update(ctx, &grants); err != nil {
+			log.Error(err, "unable to update SqlGrant status")
+			return ctrl.Result{}, err
+		}
 	}
 
 	return scheduledResult, nil
diff --git a/controllers/sqlhost_controller.go b/controllers/sqlhost_controller.go
index 4a31155..2ad8d50 100644
--- a/controllers/sqlhost_controller.go
+++ b/controllers/sqlhost_controller.go
@@ -30,6 +30,7 @@ import (
 
 	"github.com/prometheus/client_golang/prometheus"
 	steniciov1alpha1 "github.com/stenic/sql-operator/api/v1alpha1"
+	"github.com/stenic/sql-operator/drivers"
 )
 
 // SqlHostReconciler reconciles a SqlHost object
@@ -67,6 +68,16 @@ func (r *SqlHostReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}
 
+	driver, err := drivers.GetDriver(host)
+	if err != nil {
+		return ctrl.Result{}, err
+	}
+
+	if err := driver.InitOwnerSchema(ctx); err != nil {
+		r.Recorder.Event(&host, "Warning", "Error", err.Error())
+		return ctrl.Result{RequeueAfter: r.RefreshRate * 10}, err
+	}
+
 	scheduledResult := ctrl.Result{RequeueAfter: r.RefreshRate}
 
 	finalizerName := "stenic.io/sqlhost-deletion"
diff --git a/controllers/sqluser_controller.go b/controllers/sqluser_controller.go
index 87ba3d7..66d53c3 100644
--- a/controllers/sqluser_controller.go
+++ b/controllers/sqluser_controller.go
@@ -79,6 +79,19 @@ func (r *SqlUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 	if err != nil {
 		return ctrl.Result{}, err
 	}
+
+	// Provide ownership data
+	err = driver.SetOwnershipData(ctx, drivers.OwnerShipData{
+		Type:     drivers.OwnerShipTypeUser,
+		Name:     user.Spec.Credentials.Username,
+		Resource: req.NamespacedName.String(),
+		OwnerID:  user.Status.OwnerID,
+	})
+	if err != nil {
+		r.Recorder.Event(&host, "Warning", "Error", err.Error())
+		return ctrl.Result{RequeueAfter: r.RefreshRate * 2}, err
+	}
+
 	scheduledResult := ctrl.Result{RequeueAfter: r.RefreshRate}
 
 	finalizerName := "stenic.io/sqluser-deletion"
@@ -107,7 +120,7 @@ func (r *SqlUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 			if len(children.Items) > 0 {
 				err := fmt.Errorf(
 					"%s - [%s/%s] ...",
-					"Can't delete, found other referencing this object",
+					"can't delete, found other referencing this object",
 					children.Items[0].Namespace,
 					children.Items[0].Name,
 				)
@@ -116,15 +129,22 @@ func (r *SqlUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 				// might have been faster than referenced object, reschedule.
 				return scheduledResult, err
 			}
+			r.Recorder.Event(&user, "Normal", "Delete", "Validated no child objects")
 
-			if user.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
-				// delete the user
-				if err = driver.DeleteUser(ctx, user); err != nil {
-					r.Recorder.Event(&user, "Warning", "Error", err.Error())
-					sqlOperatorActionsFailures.With(promLabels).Inc()
-					return ctrl.Result{}, err
-				}
+			// Cleanup ref
+			if err := driver.DeleteOwnerState(ctx); err != nil {
+				log.Error(err, "unable to cleanup ownership")
+				return ctrl.Result{}, err
 			}
+			r.Recorder.Event(&user, "Normal", "Delete", "Removed owner references")
+
+			// delete the user
+			if err = driver.DeleteUser(ctx, user); err != nil {
+				r.Recorder.Event(&user, "Warning", "Error", err.Error())
+				sqlOperatorActionsFailures.With(promLabels).Inc()
+				return ctrl.Result{}, err
+			}
+			r.Recorder.Event(&user, "Normal", "Delete", "Deleted mysql object")
 
 			// remove our finalizer from the list and update it.
 			controllerutil.RemoveFinalizer(&user, finalizerName)
@@ -137,21 +157,16 @@ func (r *SqlUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 		return ctrl.Result{}, nil
 	}
 
-	// Deduplicate control loop
-	if user.Status.LastModifiedTimestamp != nil && time.Since(user.Status.LastModifiedTimestamp.Time) < r.RefreshRate {
+	if driver.Noop {
+		r.Recorder.Event(&user, "Normal", "Noop", "Determined object is not owned")
 		return ctrl.Result{}, nil
 	}
 
-	if !user.Status.Created {
-		user.Status.Created = true
-		user.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
+	// Deduplicate control loop
+	if user.Status.LastModifiedTimestamp != nil && time.Since(user.Status.LastModifiedTimestamp.Time) < r.RefreshRate {
+		return ctrl.Result{}, nil
 	}
-	user.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
 
-	if err := r.Status().Update(ctx, &user); err != nil {
-		log.Error(err, "unable to update SqlUser status")
-		return ctrl.Result{}, err
-	}
 	count, err := driver.UpsertUser(ctx, user)
 	if err != nil {
 		log.Error(err, "failed to create SqlUser")
@@ -162,6 +177,18 @@ func (r *SqlUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
 	if count > 0 {
 		r.Recorder.Event(&user, "Normal", "Changed", fmt.Sprintf("%d queries executed", count))
 		sqlOperatorQueries.With(promLabels).Add(float64(count))
+
+		if !user.Status.Created {
+			user.Status.Created = true
+			user.Status.CreationTimestamp = &metav1.Time{Time: time.Now()}
+		}
+		user.Status.LastModifiedTimestamp = &metav1.Time{Time: time.Now()}
+		user.Status.OwnerID = driver.GetOwnerID()
+
+		if err := r.Status().Update(ctx, &user); err != nil {
+			log.Error(err, "unable to update SqlUser status")
+			return ctrl.Result{}, err
+		}
 	}
 
 	return scheduledResult, nil
diff --git a/docs/extras/ownership.md b/docs/extras/ownership.md
new file mode 100644
index 0000000..91b61a9
--- /dev/null
+++ b/docs/extras/ownership.md
@@ -0,0 +1,21 @@
+# Ownership
+
+Sql-operator comes with ownership tracking since
+[v1.13.0](https://github.com/stenic/sql-operator/releases/tag/v1.13.0). Ownership tracking ensures that only
+1 object can alter the Sql resources.
+
+Each time an object gets reconciled, a check will be performed to validate that the kubernetes object is indeed
+the object managing the Sql resource. An additional status field has been added called `OwnerID`. The tracking 
+is implemented on each driver.
+
+The following checks are performed:
+
+```
+Is the object known in the reference table?
+  -> YES: Does the OwnerID match?
+    -> YES: IsOwner
+	-> NO: NotOwner
+  -> NO: Does the resource exist?
+    -> YES: NotOwner
+	-> NO: NonExisting
+```
diff --git a/drivers/decorator.go b/drivers/decorator.go
new file mode 100644
index 0000000..d628790
--- /dev/null
+++ b/drivers/decorator.go
@@ -0,0 +1,105 @@
+package drivers
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/google/uuid"
+	steniciov1alpha1 "github.com/stenic/sql-operator/api/v1alpha1"
+)
+
+type driverDecorator struct {
+	driver        Driver
+	Noop          bool
+	ownerShipData OwnerShipData
+}
+
+func (d *driverDecorator) UpsertUser(ctx context.Context, user steniciov1alpha1.SqlUser) (int64, error) {
+	if !d.Noop {
+		return d.driver.UpsertUser(ctx, user)
+	}
+	return 0, nil
+}
+
+func (d *driverDecorator) DeleteUser(ctx context.Context, user steniciov1alpha1.SqlUser) error {
+	if user.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
+		return d.driver.DeleteUser(ctx, user)
+	}
+	return nil
+}
+
+func (d *driverDecorator) UpsertDatabase(ctx context.Context, database steniciov1alpha1.SqlDatabase) (int64, error) {
+	if !d.Noop {
+		return d.driver.UpsertDatabase(ctx, database)
+	}
+	return 0, nil
+}
+
+func (d *driverDecorator) DeleteDatabase(ctx context.Context, database steniciov1alpha1.SqlDatabase) error {
+	if !d.Noop && database.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
+		return d.driver.DeleteDatabase(ctx, database)
+	}
+	return nil
+}
+
+func (d *driverDecorator) UpsertGrants(ctx context.Context, grant steniciov1alpha1.SqlGrant, user steniciov1alpha1.SqlUser, database steniciov1alpha1.SqlDatabase) (int64, error) {
+	if !d.Noop {
+		return d.driver.UpsertGrants(ctx, grant, user, database)
+	}
+	return 0, nil
+}
+
+func (d *driverDecorator) DeleteGrants(ctx context.Context, grant steniciov1alpha1.SqlGrant, user steniciov1alpha1.SqlUser, database steniciov1alpha1.SqlDatabase) error {
+	if !d.Noop && grant.Spec.CleanupPolicy == steniciov1alpha1.CleanupPolicyDelete {
+		return d.driver.DeleteGrants(ctx, grant, user, database)
+	}
+	return nil
+}
+
+func (d *driverDecorator) DeleteOwnerState(ctx context.Context) error {
+	return d.driver.DeleteOwnerState(ctx, d.ownerShipData)
+}
+
+func (d *driverDecorator) SetOwnershipData(ctx context.Context, data OwnerShipData) error {
+	d.ownerShipData = data
+	if d.ownerShipData.OwnerID == "" {
+		d.ownerShipData.OwnerID = steniciov1alpha1.OwnerID(uuid.New().String())
+	}
+
+	err := d.checkOwner(ctx)
+	if err != nil {
+		d.Noop = true
+	}
+
+	return err
+}
+
+func (d *driverDecorator) InitOwnerSchema(ctx context.Context) error {
+	return d.driver.InitOwnerSchema(ctx)
+}
+
+func (d *driverDecorator) GetOwnerID() steniciov1alpha1.OwnerID {
+	return d.ownerShipData.OwnerID
+}
+
+func (d *driverDecorator) checkOwner(ctx context.Context) error {
+	ownerState, err := d.driver.GetOwnerState(ctx, d.ownerShipData)
+	if err != nil {
+		return err
+	}
+	switch ownerState {
+	case NonExisting:
+		if err := d.driver.SetOwnerState(ctx, d.ownerShipData); err != nil {
+			return fmt.Errorf("failed to claim ownership - %s", err.Error())
+		}
+		return nil
+	case NotOwner:
+		// We are not managing this resource)
+		return fmt.Errorf("resource already exists and will not managed by this sqlOperator")
+	case IsOwner:
+		// All good, proceed
+		return nil
+	default:
+		return fmt.Errorf("unknown ownerState '%s'", ownerState)
+	}
+}
diff --git a/drivers/driver.go b/drivers/driver.go
index ff70dc6..d857343 100644
--- a/drivers/driver.go
+++ b/drivers/driver.go
@@ -9,17 +9,45 @@ import (
 	steniciov1alpha1 "github.com/stenic/sql-operator/api/v1alpha1"
 )
 
-func GetDriver(host steniciov1alpha1.SqlHost) (Driver, error) {
+func GetDriver(host steniciov1alpha1.SqlHost) (*driverDecorator, error) {
+	var driver Driver
 	switch host.Spec.Engine {
 	case steniciov1alpha1.EngineTypeMysql:
-		return &MySqlDriver{
+		driver = &MySqlDriver{
 			Host: host,
+		}
+	}
+
+	if driver != nil {
+		return &driverDecorator{
+			driver: driver,
 		}, nil
 	}
 
 	return nil, errors.New("Driver could not be resolved")
 }
 
+type OwnerShipType string
+
+type OwnerShipData struct {
+	Type     OwnerShipType
+	Name     string
+	Resource string
+	OwnerID  steniciov1alpha1.OwnerID
+}
+
+type OwnerState string
+
+const (
+	IsOwner     OwnerState = "IsOwner"
+	NotOwner    OwnerState = "NotOwner"
+	NonExisting OwnerState = "NonExisting"
+
+	OwnerShipTypeDatabase OwnerShipType = "OwnerShipTypeDatabase"
+	OwnerShipTypeUser     OwnerShipType = "OwnerShipTypeUser"
+	OwnerShipTypeGrant    OwnerShipType = "OwnerShipTypeGrant"
+)
+
 type Driver interface {
 	UpsertUser(context.Context, steniciov1alpha1.SqlUser) (int64, error)
 	DeleteUser(context.Context, steniciov1alpha1.SqlUser) error
@@ -27,4 +55,8 @@ type Driver interface {
 	DeleteDatabase(context.Context, steniciov1alpha1.SqlDatabase) error
 	UpsertGrants(context.Context, steniciov1alpha1.SqlGrant, steniciov1alpha1.SqlUser, steniciov1alpha1.SqlDatabase) (int64, error)
 	DeleteGrants(context.Context, steniciov1alpha1.SqlGrant, steniciov1alpha1.SqlUser, steniciov1alpha1.SqlDatabase) error
+	InitOwnerSchema(context.Context) error
+	SetOwnerState(context.Context, OwnerShipData) error
+	DeleteOwnerState(context.Context, OwnerShipData) error
+	GetOwnerState(context.Context, OwnerShipData) (OwnerState, error)
 }
diff --git a/drivers/mysql.go b/drivers/mysql.go
index 9f4ab4b..c5cab1e 100644
--- a/drivers/mysql.go
+++ b/drivers/mysql.go
@@ -3,7 +3,6 @@ package drivers
 import (
 	"context"
 	"database/sql"
-	"encoding/json"
 	"fmt"
 	"regexp"
 	"strings"
@@ -14,6 +13,22 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/log"
 )
 
+var refSchema = "sqloperator_schema"
+var refSchemaDatabase = "sqldatabase_ref"
+var refSchemaUser = "sqluser_ref"
+var refSchemaGrant = "sqlgrant_ref"
+
+var createOwnerSchema = fmt.Sprintf(`CREATE DATABASE IF NOT EXISTS %s;`, refSchema)
+var createOwnerSchemaTableTpl = fmt.Sprintf(`
+CREATE TABLE IF NOT EXISTS %s.%%s (
+  id varchar(64) NOT NULL COMMENT 'Unique identifier',
+  name varchar(253) NOT NULL COMMENT 'Sql object name',
+  owner varchar(253) NOT NULL COMMENT 'Controller name',
+  resource varchar(507) NOT NULL COMMENT 'Kubernetes object reference',
+  PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+`, refSchema)
+
 type MySqlDriver struct {
 	Host steniciov1alpha1.SqlHost
 }
@@ -199,9 +214,126 @@ func (d *MySqlDriver) UpsertGrants(ctx context.Context, grants steniciov1alpha1.
 	return changeCount, err
 }
 
-func pp(a []string) string {
-	j, _ := json.Marshal(a)
-	return string(j)
+func (d *MySqlDriver) InitOwnerSchema(ctx context.Context) error {
+	db, err := d.connect()
+	if err != nil {
+		return err
+	}
+	defer db.Close()
+
+	if _, err = db.ExecContext(ctx, createOwnerSchema); err != nil {
+		return err
+	}
+	if _, err = db.ExecContext(ctx, fmt.Sprintf(createOwnerSchemaTableTpl, refSchemaDatabase)); err != nil {
+		return err
+	}
+	if _, err = db.ExecContext(ctx, fmt.Sprintf(createOwnerSchemaTableTpl, refSchemaUser)); err != nil {
+		return err
+	}
+	if _, err = db.ExecContext(ctx, fmt.Sprintf(createOwnerSchemaTableTpl, refSchemaGrant)); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (d *MySqlDriver) SetOwnerState(ctx context.Context, data OwnerShipData) error {
+	db, err := d.connect()
+	if err != nil {
+		return err
+	}
+	defer db.Close()
+
+	_, err = db.ExecContext(
+		ctx,
+		fmt.Sprintf("INSERT IGNORE INTO %s (id, resource, name, owner) VALUES (?, ?, ?, ?) ;", d.getOwnerDBTable(data)),
+		data.OwnerID, data.Resource, data.Name, "sql-operator",
+	)
+
+	return err
+}
+
+func (d *MySqlDriver) GetOwnerState(ctx context.Context, data OwnerShipData) (OwnerState, error) {
+	state := NonExisting
+	db, err := d.connect()
+	if err != nil {
+		return state, err
+	}
+	defer db.Close()
+
+	sqlStatement := fmt.Sprintf("SELECT s.id FROM %s s WHERE resource=? LIMIT 1;", d.getOwnerDBTable(data))
+	var dbID string
+	row := db.QueryRowContext(ctx, sqlStatement, data.Resource)
+	switch err := row.Scan(&dbID); err {
+	case nil:
+		if dbID == string(data.OwnerID) {
+			return IsOwner, nil
+		}
+		return NotOwner, nil
+	case sql.ErrNoRows:
+		break
+	default:
+		return NotOwner, err
+	}
+
+	switch data.Type {
+	case OwnerShipTypeDatabase:
+		results, err := db.QueryContext(ctx, "SHOW databases;")
+		if err != nil {
+			return state, err
+		}
+		defer results.Close()
+
+		for results.Next() {
+			var dbName string
+			if err = results.Scan(&dbName); err != nil {
+				return state, err
+			}
+			if dbName == data.Name {
+				return NotOwner, nil
+			}
+		}
+	case OwnerShipTypeUser:
+		sqlStatement := fmt.Sprintf("SELECT count(u.id) FROM %s s WHERE resource=? LIMIT 1;", d.getOwnerDBTable(data))
+		var matchCount int
+		row := db.QueryRowContext(ctx, sqlStatement, data.Resource)
+		if err := row.Scan(&matchCount); err != nil {
+			return NotOwner, err
+		}
+		if matchCount >= 1 {
+			return NotOwner, nil
+		}
+	}
+
+	return NonExisting, nil
+}
+
+func (d *MySqlDriver) DeleteOwnerState(ctx context.Context, data OwnerShipData) error {
+	db, err := d.connect()
+	if err != nil {
+		return err
+	}
+	defer db.Close()
+
+	_, err = db.ExecContext(
+		ctx,
+		fmt.Sprintf("DELETE FROM %s WHERE id = ? AND resource = ? LIMIT 1;", d.getOwnerDBTable(data)),
+		data.OwnerID, data.Resource,
+	)
+
+	return err
+}
+
+func (d *MySqlDriver) getOwnerDBTable(data OwnerShipData) string {
+	switch data.Type {
+	case OwnerShipTypeDatabase:
+		return fmt.Sprintf("`%s`.%s", refSchema, refSchemaDatabase)
+	case OwnerShipTypeUser:
+		return fmt.Sprintf("`%s`.%s", refSchema, refSchemaUser)
+	case OwnerShipTypeGrant:
+		return fmt.Sprintf("`%s`.%s", refSchema, refSchemaGrant)
+	default:
+		panic("unhandled ownership type")
+	}
 }
 
 func difference(a, b []string) []string {
diff --git a/go.mod b/go.mod
index 139df8e..407e3a8 100644
--- a/go.mod
+++ b/go.mod
@@ -4,6 +4,7 @@ go 1.16
 
 require (
 	github.com/go-sql-driver/mysql v1.6.0
+	github.com/google/uuid v1.3.0
 	github.com/onsi/ginkgo v1.16.5
 	github.com/onsi/gomega v1.17.0
 	github.com/prometheus/client_golang v1.11.0
diff --git a/go.sum b/go.sum
index 96ae376..cefb909 100644
--- a/go.sum
+++ b/go.sum
@@ -203,8 +203,9 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
 github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
