diff --git a/client/dconf-client.vala b/client/dconf-client.vala
index 472e544..03e2cf1 100644
--- a/client/dconf-client.vala
+++ b/client/dconf-client.vala
@@ -25,6 +25,10 @@ namespace DConf {
 				parameters.get ("(&s)", out path);
 				items = new string[0];
 				tag = "";
+			} else if (signal_name == "DatabaseChange" && parameters.is_of_type ((VariantType) "(s)")) {
+				parameters.get ("(&s)", out path);
+				items = new string[0];
+				tag = "";
 			} else {
 				assert_not_reached ();
 			}
@@ -280,6 +284,42 @@ namespace DConf {
 		 **/
 		public bool watch (string path, Cancellable? cancellable = null) throws GLib.Error {
 			call_sync (engine.watch (path), null, cancellable);
+
+			/*
+			 * Add a timeout which checks for changes of databases each minute.
+			 */
+			var time = new TimeoutSource (60000);
+			time.set_callback (() => {
+				GLib.DBusConnection session_bus = Bus.get_sync (BusType.SESSION);
+				Variant             changed_keys = engine.get_changed (path);
+
+				if (changed_keys != null && changed_keys.is_of_type ((VariantType) "(a(ss))")) {
+					Variant items = changed_keys.get_child_value (0);
+
+					if (items.is_of_type ((VariantType) "a(ss)")) {
+						for (int i = 0; i < items.n_children (); i++) {
+							Variant item = items.get_child_value (i);
+
+							if (item.is_of_type ((VariantType) "(ss)")) {
+								string changed_database = item.get_child_value (0).get_string ();
+								string changed_key = item.get_child_value (1).get_string ();
+
+								session_bus.emit_signal (null,
+							        	                 "/ca/desrt/dconf/Writer/" + changed_database,
+								                         "ca.desrt.dconf.Writer",
+											 "DatabaseChange",
+											 new Variant ("(s)", changed_key));
+								session_bus.flush_sync ();
+							}
+						}
+					}
+				}
+
+				return true;
+			});
+
+			time.attach (null);
+
 			return true;
 		}
 
diff --git a/client/engine.vapi b/client/engine.vapi
index d90063c..4adfb95 100644
--- a/client/engine.vapi
+++ b/client/engine.vapi
@@ -13,6 +13,7 @@ namespace DConf {
 		internal string[] list (string dir, void*junk = null);
 		internal EngineMessage watch (string name);
 		internal EngineMessage unwatch (string name);
+		internal GLib.Variant? get_changed (string path);
 	}
 
 	struct EngineMessage {
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index 8f5c613..bf5ad65 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -30,6 +30,8 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h>
+#include <glib/gstdio.h>
+#include <sys/vfs.h>
 
 void
 dconf_engine_message_destroy (DConfEngineMessage *dcem)
@@ -84,6 +86,7 @@ struct _DConfEngine
   gchar      *bus_types;
   gchar     **names;
   gint        n_dbs;
+  time_t     *mtimes;
 };
 
 static void
@@ -123,6 +126,7 @@ dconf_engine_setup_user (DConfEngine *engine)
 
       if (engine->shm)
         {
+          GStatBuf buf;
           gchar *filename;
 
           filename = g_build_filename (g_get_user_config_dir (),
@@ -130,6 +134,8 @@ dconf_engine_setup_user (DConfEngine *engine)
                                        engine->names[0],
                                        NULL);
           engine->gvdbs[0] = gvdb_table_new (filename, FALSE, NULL);
+          engine->mtimes[0] = g_stat (filename, &buf) == 0 ? buf.st_mtime : 0;
+
           g_free (filename);
         }
     }
@@ -278,6 +284,12 @@ dconf_engine_new (const gchar *profile)
 {
   DConfEngine *engine;
   gint i;
+  gboolean on_nfs;
+  gchar *filename;
+  GStatBuf buf;
+#if !defined(G_OS_WIN32) || !defined(_MSC_VER)
+  struct statfs fsbuf;
+#endif
 
   engine = g_slice_new (DConfEngine);
   g_mutex_init (&engine->lock);
@@ -315,17 +327,46 @@ dconf_engine_new (const gchar *profile)
   engine->object_paths = g_new (gchar *, engine->n_dbs);
   engine->gvdbs = g_new0 (GvdbTable *, engine->n_dbs);
   engine->lock_tables = g_new0 (GvdbTable *, engine->n_dbs);
+  engine->mtimes = g_new0 (time_t, engine->n_dbs);
   engine->bus_types = g_strdup ("eyyyyyyyyyyyyy");
   engine->state = 0;
 
   for (i = 0; i < engine->n_dbs; i++)
-    if (engine->names[i])
-        engine->object_paths[i] = g_strjoin (NULL,
-                                             "/ca/desrt/dconf/Writer/",
-                                             engine->names[i],
-                                             NULL);
-    else
-      engine->object_paths[i] = NULL;
+    {
+
+      if (engine->names[i])
+        {
+          filename = g_build_filename (g_get_user_config_dir (),
+                                       "dconf",
+                                       engine->names[i],
+                                       NULL);
+
+          on_nfs = TRUE;
+
+#if !defined(G_OS_WIN32) || !defined(_MSC_VER)
+          if (statfs (filename, &fsbuf) == 0 &&
+              fsbuf.f_type != 0x6969)
+            on_nfs = FALSE;
+#endif
+
+          if (g_stat (filename, &buf) == 0 && on_nfs)
+            engine->mtimes[i] = buf.st_mtime;
+          else
+            engine->mtimes[i] = 0;
+
+          g_free (filename);
+
+          engine->object_paths[i] = g_strjoin (NULL,
+                                               "/ca/desrt/dconf/Writer/",
+                                               engine->names[i],
+                                               NULL);
+        }
+      else
+        {
+          engine->mtimes[i] = 0;
+          engine->object_paths[i] = NULL;
+        }
+    }
 
   dconf_engine_refresh_system (engine);
   dconf_engine_setup_user (engine);
@@ -362,6 +403,7 @@ dconf_engine_free (DConfEngine *engine)
   g_free (engine->names);
   g_free (engine->gvdbs);
   g_free (engine->lock_tables);
+  g_free (engine->mtimes);
 
   g_slice_free (DConfEngine, engine);
 }
@@ -714,3 +756,215 @@ dconf_engine_decode_writability_notify (const gchar **path,
 
   return TRUE;
 }
+
+typedef struct
+{
+  GvdbTable *old_table;
+  GList     *differs;
+  gchar     *path;
+  gint       level;
+} DConfEqualState;
+
+static void
+table_walk_value (const gchar *name,
+                  gsize        name_len,
+                  GVariant    *value,
+                  gpointer     user_data)
+{
+  DConfEqualState *state = (DConfEqualState *) user_data;
+  GVariant        *old_value;
+  gchar           *path;
+
+  path = g_strconcat (state->path, name, NULL);
+  old_value = gvdb_table_get_value (state->old_table, path);
+
+  if (value &&
+      old_value &&
+      !g_variant_equal (value, old_value))
+    state->differs = g_list_prepend (state->differs, path);
+  else
+    g_free (path);
+
+  if (old_value)
+    g_variant_unref (old_value);
+}
+
+static gboolean
+table_walk_open (const gchar *name,
+                 gsize        name_len,
+                 gpointer     user_data)
+{
+  DConfEqualState *state = (DConfEqualState *) user_data;
+  gchar           *path;
+
+  if (state->level > 0)
+    {
+      path = g_strconcat (state->path, name, NULL);
+      g_free (state->path);
+      state->path = path;
+    }
+
+  state->level++;
+
+  return TRUE;
+}
+
+static void
+table_walk_close (gsize    name_len,
+                  gpointer user_data)
+{
+  DConfEqualState *state = (DConfEqualState *) user_data;
+  gchar           *path;
+
+  if (state->level > 0)
+    {
+      path = g_strndup (state->path, strlen (state->path) - name_len);
+      g_free (state->path);
+      state->path = path;
+    }
+
+  state->level--;
+}
+
+/*
+ * Compares mmapped version of database 'name' with the
+ * version on disc and returns a list of changed values
+ * for given path (relative or absolute).
+ * Also refreshes user database at the end.
+ */
+static GList *
+dconf_engine_list_changed (DConfEngine *engine,
+                           const gchar *name,
+                           const gchar *path)
+{
+  GvdbTable *table;
+  GList     *result = NULL;
+  gchar     *filename;
+  gint       i;
+
+  if (name && path)
+    {
+      filename = g_build_filename (g_get_user_config_dir (),
+                                   "dconf",
+                                   name,
+                                   NULL);
+      table = gvdb_table_new (filename, FALSE, NULL);
+      g_free (filename);
+
+      if (table)
+        {
+          for (i = 0; i < engine->n_dbs; i++)
+            {
+              if (g_strcmp0 (engine->names[i], name) == 0)
+                {
+                  if (g_str_has_suffix (path, "/"))
+                    {
+                      DConfEqualState state;
+
+                      state.old_table = engine->gvdbs[i];
+                      state.differs = NULL;
+                      state.path = g_strdup (path);
+                      state.level = 0;
+
+                      gvdb_table_walk (table, path,
+                                       table_walk_open,
+                                       table_walk_value,
+                                       table_walk_close,
+                                       &state);
+
+                      g_free (state.path);
+
+                      result = state.differs;
+                    }
+                  else
+                    {
+                      GVariant *old_value;
+                      GVariant *new_value;
+
+                      old_value = gvdb_table_get_value (engine->gvdbs[i], path);
+                      new_value = gvdb_table_get_value (table, path);
+
+                      if (old_value &&
+                          new_value &&
+                          !g_variant_equal (old_value, new_value))
+                        result = g_list_prepend (result, g_strdup (path));
+
+                      if (old_value)
+                        g_variant_unref (old_value);
+
+                      if (new_value)
+                        g_variant_unref (new_value);
+                    }
+                  break;
+                }
+            }
+        }
+
+      gvdb_table_unref (table);
+
+      /* This should be probably somewhere else */
+      dconf_engine_setup_user (engine);
+    }
+
+  return result;
+}
+
+/*
+ * Return list of tuples containing name of changed database and name of changed key
+ * for the given path.
+ * The new database if read from filesystem, the old from the given engine.
+ */
+GVariant *
+dconf_engine_get_changed (DConfEngine *engine,
+                          const gchar *path)
+{
+  GVariantBuilder  array_builder;
+  GVariant        *result = NULL;
+  gboolean         changed = FALSE;
+  gint             i;
+
+  g_mutex_lock (&engine->lock);
+
+  g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ss)"));
+
+  for (i = 0; i < engine->n_dbs; i++)
+    {
+      GStatBuf  buf;
+      gchar    *filename;
+
+      if (engine->names[i] && engine->mtimes[i] != 0)
+        {
+          filename = g_build_filename (g_get_user_config_dir (),
+                                       "dconf",
+                                       engine->names[i],
+                                       NULL);
+          if (g_stat (filename, &buf) == 0)
+            {
+              if (buf.st_mtime > engine->mtimes[i])
+                {
+                  GList *iter;
+                  GList *changed_paths;
+
+                  changed_paths = dconf_engine_list_changed (engine, engine->names[i], path);
+
+                  for (iter = changed_paths; iter; iter = g_list_next (iter))
+                    {
+                      g_variant_builder_add (&array_builder, "(ss)", (gchar *) engine->names[i], (gchar *) iter->data);
+                      changed = TRUE;
+                    }
+
+                  g_list_free_full (changed_paths, g_free);
+                }
+            }
+
+          g_free (filename);
+        }
+    }
+
+  if (changed)
+    result = g_variant_new ("(a(ss))", &array_builder);
+
+  g_mutex_unlock (&engine->lock);
+
+  return result;
+}
diff --git a/engine/dconf-engine.h b/engine/dconf-engine.h
index 5769cab..fe13f7c 100644
--- a/engine/dconf-engine.h
+++ b/engine/dconf-engine.h
@@ -144,4 +144,7 @@ gboolean                dconf_engine_decode_writability_notify          (const g
                                                                          const gchar             *iface,
                                                                          const gchar             *method,
                                                                          GVariant                *body);
+G_GNUC_INTERNAL
+GVariant *              dconf_engine_get_changed                        (DConfEngine             *engine,
+                                                                         const gchar             *path);
 #endif /* __dconf_engine_h__ */
diff --git a/service/dconf-rebuilder.c b/service/dconf-rebuilder.c
index d7f4cb3..96ffad9 100644
--- a/service/dconf-rebuilder.c
+++ b/service/dconf-rebuilder.c
@@ -22,6 +22,8 @@
 #include "dconf-rebuilder.h"
 
 #include <string.h>
+#include <fcntl.h>
+#include <errno.h>
 
 #include "gvdb-reader.h"
 #include "gvdb-builder.h"
@@ -191,9 +193,33 @@ dconf_rebuilder_rebuild (const gchar  *filename,
                                 0, keys, values, n_items };
   gboolean success;
   GvdbTable *old;
+  struct flock lock;
+  int          lock_fd = -1;
 
   state.table = gvdb_hash_table_new (NULL, NULL);
 
+  if ((lock_fd = open (filename, O_WRONLY | O_SYNC)) != -1)
+    {
+      lock.l_whence = SEEK_SET;
+      lock.l_start = 0;
+      lock.l_len = 0;
+      lock.l_type = F_WRLCK;
+
+      /* Create a lock on the file 'filename' */
+      if (fcntl (lock_fd, F_SETLKW, &lock) == -1)
+        {
+          g_warning ("Can not get lock on '%s': %s",
+                     filename,
+                     g_strerror (errno));
+        }
+    }
+  else
+    {
+      g_warning ("Can not open '%s': %s",
+                 filename,
+                 g_strerror (errno));
+    }
+
   if ((old = gvdb_table_new (filename, FALSE, NULL)))
     {
       gvdb_table_walk (old, "/",
@@ -208,6 +234,12 @@ dconf_rebuilder_rebuild (const gchar  *filename,
     dconf_rebuilder_put_item (&state);
 
   success = gvdb_table_write_contents (state.table, filename, FALSE, error);
+
+  if (lock_fd != -1)
+    {
+      close (lock_fd);
+    }
+
   g_hash_table_unref (state.table);
 
   return success;
