diff --git a/tools/mesh/cfgcli.c b/tools/mesh/cfgcli.c
index d8eee4edc..485d13b5a 100644
--- a/tools/mesh/cfgcli.c
+++ b/tools/mesh/cfgcli.c
@@ -447,13 +447,12 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
 		if (!cmd)
 			break;
 
-		if (cmd->opcode == OP_APPKEY_ADD) {
-			if (remote_add_app_key(src, app_idx))
-				mesh_db_node_app_key_add(src, app_idx);
-		} else if (cmd->opcode == OP_APPKEY_DELETE) {
-			if (remote_del_app_key(src, app_idx))
-				mesh_db_node_app_key_del(src, app_idx);
-		}
+		if (cmd->opcode == OP_APPKEY_ADD)
+			remote_add_app_key(src, app_idx, true);
+		else if (cmd->opcode == OP_APPKEY_DELETE)
+			remote_del_app_key(src, app_idx);
+		else if (cmd->opcode == OP_APPKEY_UPDATE)
+			remote_update_app_key(src, app_idx, true, true);
 
 		break;
 
@@ -492,13 +491,12 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
 		if (!cmd)
 			break;
 
-		if (cmd->opcode == OP_NETKEY_ADD) {
-			if (remote_add_net_key(src, net_idx))
-				mesh_db_node_net_key_add(src, net_idx);
-		} else if (cmd->opcode == OP_NETKEY_DELETE) {
-			if (remote_del_net_key(src, net_idx))
-				mesh_db_node_net_key_del(src, net_idx);
-		}
+		if (cmd->opcode == OP_NETKEY_ADD)
+			remote_add_net_key(src, net_idx, true);
+		else if (cmd->opcode == OP_NETKEY_DELETE)
+			remote_del_net_key(src, net_idx);
+		else if (cmd->opcode == OP_NETKEY_UPDATE)
+			remote_update_net_key(src, net_idx, true, true);
 
 		break;
 
@@ -534,6 +532,13 @@ static bool msg_recvd(uint16_t src, uint16_t idx, uint8_t *data,
 
 		bt_shell_printf("\tNetKey %u (0x%3.3x)\n", net_idx, net_idx);
 		bt_shell_printf("\tKR Phase %2.2x\n", data[3]);
+
+		if (data[0] != MESH_STATUS_SUCCESS)
+			return true;
+
+		if (data[3] == KEY_REFRESH_PHASE_NONE)
+			remote_finish_key_refresh(src, net_idx);
+
 		break;
 
 	case OP_MODEL_APP_STATUS:
diff --git a/tools/mesh/mesh-db.c b/tools/mesh/mesh-db.c
index 5b3c4b2f7..a57a5d547 100644
--- a/tools/mesh/mesh-db.c
+++ b/tools/mesh/mesh-db.c
@@ -200,6 +200,38 @@ static bool write_int(json_object *jobj, const char *keyword, int val)
 	return true;
 }
 
+static bool get_bool(json_object *jobj, const char *keyword, bool *value)
+{
+	json_object *jvalue;
+
+	if (!json_object_object_get_ex(jobj, keyword, &jvalue))
+		return false;
+
+	if (json_object_get_type(jvalue) != json_type_boolean) {
+		l_error("Error: %s should contain a boolean value\n",
+								keyword);
+		return false;
+	}
+
+	*value = json_object_get_boolean(jvalue);
+
+	return true;
+}
+
+static bool write_bool(json_object *jobj, const char *keyword, bool val)
+{
+	json_object *jval;
+
+	json_object_object_del(jobj, keyword);
+
+	jval = json_object_new_boolean(val);
+	if (!jval)
+		return false;
+
+	json_object_object_add(jobj, keyword, jval);
+	return true;
+}
+
 static json_object *get_key_object(json_object *jarray, uint16_t idx)
 {
 	int i, sz = json_object_array_length(jarray);
@@ -347,6 +379,20 @@ static uint16_t node_parse_key(json_object *jarray, int i)
 	return (uint16_t)idx;
 }
 
+static bool node_check_key_updated(json_object *jarray, int i, bool *updated)
+{
+	json_object *jkey;
+
+	jkey = json_object_array_get_idx(jarray, i);
+	if (!jkey)
+		return false;
+
+	if (!get_bool(jkey, "updated", updated))
+		return false;
+
+	return true;
+}
+
 static int compare_group_addr(const void *a, const void *b, void *user_data)
 {
 	const struct mesh_group *grp0 = a;
@@ -483,10 +529,17 @@ static void load_remotes(json_object *jcfg)
 		remote_add_node((const uint8_t *)uuid, unicast, ele_cnt,
 								key_idx);
 		for (j = 1; j < key_cnt; j++) {
+			bool updated = false;
+
 			key_idx = node_parse_key(jarray, j);
 
-			if (key_idx != KEY_IDX_INVALID)
-				remote_add_net_key(unicast, key_idx);
+			if (key_idx == KEY_IDX_INVALID)
+				continue;
+
+			remote_add_net_key(unicast, key_idx, false);
+
+			node_check_key_updated(jarray, j, &updated);
+			remote_update_net_key(unicast, key_idx, updated, false);
 		}
 
 		json_object_object_get_ex(jnode, "appKeys", &jarray);
@@ -496,10 +549,17 @@ static void load_remotes(json_object *jcfg)
 		key_cnt = json_object_array_length(jarray);
 
 		for (j = 0; j < key_cnt; j++) {
+			bool updated = false;
+
 			key_idx = node_parse_key(jarray, j);
 
-			if (key_idx != KEY_IDX_INVALID)
-				remote_add_app_key(unicast, key_idx);
+			if (key_idx == KEY_IDX_INVALID)
+				continue;
+
+			remote_add_app_key(unicast, key_idx, false);
+
+			node_check_key_updated(jarray, j, &updated);
+			remote_update_app_key(unicast, key_idx, updated, false);
 		}
 
 		load_composition(jnode, unicast);
@@ -554,28 +614,19 @@ static bool add_node_key(json_object *jobj, const char *desc, uint16_t idx)
 
 	jkey = json_object_new_object();
 
-	if (!write_int(jkey, "index", (int)idx)) {
-		json_object_put(jkey);
-		return false;
-	}
+	if (!write_int(jkey, "index", (int)idx))
+		goto fail;
+
+	if (!write_bool(jkey, "updated", false))
+		goto fail;
 
 	json_object_array_add(jarray, jkey);
 
 	return save_config();
-}
-
-bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx)
-{
-	json_object *jnode;
-
-	if (!cfg || !cfg->jcfg)
-		return false;
 
-	jnode = get_node_by_unicast(unicast);
-	if (!jnode)
-		return false;
-
-	return add_node_key(jnode, "netKeys", idx);
+fail:
+	json_object_put(jkey);
+	return false;
 }
 
 bool mesh_db_node_ttl_set(uint16_t unicast, uint8_t ttl)
@@ -628,6 +679,20 @@ static bool delete_key(json_object *jobj, const char *desc, uint16_t idx)
 	return save_config();
 }
 
+bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx)
+{
+	json_object *jnode;
+
+	if (!cfg || !cfg->jcfg)
+		return false;
+
+	jnode = get_node_by_unicast(unicast);
+	if (!jnode)
+		return false;
+
+	return add_node_key(jnode, "netKeys", idx);
+}
+
 bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t net_idx)
 {
 	json_object *jnode;
@@ -642,6 +707,45 @@ bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t net_idx)
 	return delete_key(jnode, "netKeys", net_idx);
 }
 
+static bool key_update(uint16_t unicast, int16_t idx, bool updated,
+							const char *desc)
+{
+	json_object *jnode, *jarray;
+	int i, sz;
+
+	if (!cfg || !cfg->jcfg)
+		return false;
+
+	jnode = get_node_by_unicast(unicast);
+	if (!jnode)
+		return false;
+
+	if (!json_object_object_get_ex(jnode, desc, &jarray))
+		return false;
+
+	sz = json_object_array_length(jarray);
+
+	for (i = 0; i < sz; ++i) {
+		json_object *jentry;
+		int val;
+
+		jentry = json_object_array_get_idx(jarray, i);
+
+		if (!get_int(jentry, "index", &val))
+			continue;
+
+		if ((val == idx) && write_bool(jentry, "updated", updated))
+			return save_config();
+	}
+
+	return false;
+}
+
+bool mesh_db_node_net_key_update(uint16_t unicast, uint16_t idx, bool updated)
+{
+	return key_update(unicast, idx, updated, "netKeys");
+}
+
 bool mesh_db_node_app_key_add(uint16_t unicast, uint16_t idx)
 {
 	json_object *jnode;
@@ -670,6 +774,11 @@ bool mesh_db_node_app_key_del(uint16_t unicast, uint16_t idx)
 	return delete_key(jnode, "appKeys", idx);
 }
 
+bool mesh_db_node_app_key_update(uint16_t unicast, uint16_t idx, bool updated)
+{
+	return key_update(unicast, idx, updated, "appKeys");
+}
+
 static bool load_keys(json_object *jobj)
 {
 	json_object *jarray, *jentry;
diff --git a/tools/mesh/mesh-db.h b/tools/mesh/mesh-db.h
index efd579553..c1bcb3ae6 100644
--- a/tools/mesh/mesh-db.h
+++ b/tools/mesh/mesh-db.h
@@ -38,8 +38,10 @@ bool mesh_db_node_set_net_transmit(uint16_t unicast, uint8_t cnt,
 							uint16_t interval);
 bool mesh_db_node_net_key_add(uint16_t unicast, uint16_t idx);
 bool mesh_db_node_net_key_del(uint16_t unicast, uint16_t idx);
+bool mesh_db_node_net_key_update(uint16_t unicast, uint16_t idx, bool updated);
 bool mesh_db_node_app_key_add(uint16_t unicast, uint16_t idx);
 bool mesh_db_node_app_key_del(uint16_t unicast, uint16_t idx);
+bool mesh_db_node_app_key_update(uint16_t unicast, uint16_t idx, bool updated);
 bool mesh_db_node_ttl_set(uint16_t unicast, uint8_t ttl);
 bool mesh_db_node_write_mode(uint16_t unicast, const char *keyword, int value);
 bool mesh_db_node_model_binding_add(uint16_t unicast, uint8_t ele, bool vendor,
diff --git a/tools/mesh/remote.c b/tools/mesh/remote.c
index e60a3681d..5f598cb8b 100644
--- a/tools/mesh/remote.c
+++ b/tools/mesh/remote.c
@@ -25,6 +25,11 @@
 
 #define abs_diff(a, b) ((a) > (b) ? (a) - (b) : (b) - (a))
 
+struct remote_key {
+	uint16_t idx;
+	bool updated;
+};
+
 struct remote_node {
 	uint16_t unicast;
 	struct l_queue *net_keys;
@@ -42,20 +47,6 @@ struct rejected_addr {
 static struct l_queue *nodes;
 static struct l_queue *reject_list;
 
-static bool key_present(struct l_queue *keys, uint16_t app_idx)
-{
-	const struct l_queue_entry *l;
-
-	for (l = l_queue_get_entries(keys); l; l = l->next) {
-		uint16_t idx = L_PTR_TO_UINT(l->data);
-
-		if (idx == app_idx)
-			return true;
-	}
-
-	return false;
-}
-
 static int compare_mod_id(const void *a, const void *b, void *user_data)
 {
 	uint32_t id1 = L_PTR_TO_UINT(a);
@@ -102,12 +93,20 @@ static bool match_node_addr(const void *a, const void *b)
 	return false;
 }
 
+static bool match_key(const void *a, const void *b)
+{
+	const struct remote_key *key = a;
+	uint16_t idx = L_PTR_TO_UINT(b);
+
+	return (key->idx == idx);
+}
+
 static bool match_bound_key(const void *a, const void *b)
 {
-	uint16_t app_idx = L_PTR_TO_UINT(a);
+	const struct remote_key *app_key = a;
 	uint16_t net_idx = L_PTR_TO_UINT(b);
 
-	return (net_idx == keys_get_bound_key(app_idx));
+	return (net_idx == keys_get_bound_key(app_key->idx));
 }
 
 uint8_t remote_del_node(uint16_t unicast)
@@ -142,6 +141,7 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
 					uint8_t ele_cnt, uint16_t net_idx)
 {
 	struct remote_node *rmt;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(unicast));
 	if (rmt)
@@ -153,7 +153,10 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
 	rmt->num_ele = ele_cnt;
 	rmt->net_keys = l_queue_new();
 
-	l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
+	key = l_new(struct remote_key, 1);
+	key->idx = net_idx;
+
+	l_queue_push_tail(rmt->net_keys, key);
 
 	rmt->els = l_new(struct l_queue *, ele_cnt);
 
@@ -161,6 +164,7 @@ bool remote_add_node(const uint8_t uuid[16], uint16_t unicast,
 		nodes = l_queue_new();
 
 	l_queue_insert(nodes, rmt, compare_unicast, NULL);
+
 	return true;
 }
 
@@ -188,49 +192,84 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
 	return true;
 }
 
-bool remote_add_net_key(uint16_t addr, uint16_t net_idx)
+bool remote_add_net_key(uint16_t addr, uint16_t net_idx, bool save)
 {
 	struct remote_node *rmt;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
 	if (!rmt)
 		return false;
 
-	if (key_present(rmt->net_keys, net_idx))
-		return false;
+	if (l_queue_find(rmt->net_keys, match_key, L_UINT_TO_PTR(net_idx)))
+		return true;
 
-	l_queue_push_tail(rmt->net_keys, L_UINT_TO_PTR(net_idx));
-	return true;
+	key = l_new(struct remote_key, 1);
+	key->idx = net_idx;
+
+	l_queue_push_tail(rmt->net_keys, key);
+
+	if (save)
+		return mesh_db_node_net_key_add(addr, net_idx);
+	else
+		return true;
 }
 
 bool remote_del_net_key(uint16_t addr, uint16_t net_idx)
 {
 	struct remote_node *rmt;
-	void *data;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
 	if (!rmt)
 		return false;
 
-	if (!l_queue_remove(rmt->net_keys, L_UINT_TO_PTR(net_idx)))
+	key = l_queue_remove_if(rmt->net_keys, match_key,
+							L_UINT_TO_PTR(net_idx));
+	if (!key)
 		return false;
 
-	data = l_queue_remove_if(rmt->app_keys, match_bound_key,
+	mesh_db_node_net_key_del(addr, net_idx);
+
+	l_free(key);
+	key = l_queue_remove_if(rmt->app_keys, match_bound_key,
 						L_UINT_TO_PTR(net_idx));
-	while (data) {
-		uint16_t app_idx = (uint16_t) L_PTR_TO_UINT(data);
 
-		mesh_db_node_app_key_del(rmt->unicast, app_idx);
-		data = l_queue_remove_if(rmt->app_keys, match_bound_key,
+	while (key) {
+		mesh_db_node_app_key_del(rmt->unicast, key->idx);
+		l_free(key);
+
+		key = l_queue_remove_if(rmt->app_keys, match_bound_key,
 						L_UINT_TO_PTR(net_idx));
 	}
 
 	return true;
 }
 
-bool remote_add_app_key(uint16_t addr, uint16_t app_idx)
+bool remote_update_net_key(uint16_t addr, uint16_t net_idx, bool update,
+								bool save)
+{
+	struct remote_node *rmt;
+	struct remote_key *key;
+
+	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+	if (!rmt)
+		return false;
+
+	key = l_queue_find(rmt->net_keys, match_key,
+						L_UINT_TO_PTR(net_idx));
+	key->updated = update;
+
+	if (save)
+		return mesh_db_node_net_key_update(addr, net_idx, update);
+	else
+		return true;
+}
+
+bool remote_add_app_key(uint16_t addr, uint16_t app_idx, bool save)
 {
 	struct remote_node *rmt;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
 	if (!rmt)
@@ -239,44 +278,105 @@ bool remote_add_app_key(uint16_t addr, uint16_t app_idx)
 	if (!rmt->app_keys)
 		rmt->app_keys = l_queue_new();
 
-	if (key_present(rmt->app_keys, app_idx))
-		return false;
+	if (l_queue_find(rmt->app_keys, match_key, L_UINT_TO_PTR(app_idx)))
+		return true;
 
-	l_queue_push_tail(rmt->app_keys, L_UINT_TO_PTR(app_idx));
-	return true;
+	key = l_new(struct remote_key, 1);
+	key->idx = app_idx;
+
+	l_queue_push_tail(rmt->app_keys, key);
+
+	if (save)
+		return mesh_db_node_app_key_add(addr, app_idx);
+	else
+		return true;
 }
 
 bool remote_del_app_key(uint16_t addr, uint16_t app_idx)
 {
 	struct remote_node *rmt;
+	struct remote_key *key;
+
+	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+	if (!rmt)
+		return false;
+
+	key = l_queue_remove_if(rmt->app_keys, match_key,
+						L_UINT_TO_PTR(app_idx));
+	l_free(key);
+
+	return mesh_db_node_app_key_del(addr, app_idx);
+}
+
+bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
+								bool save)
+{
+	struct remote_node *rmt;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
 	if (!rmt)
 		return false;
 
-	return l_queue_remove(rmt->app_keys, L_UINT_TO_PTR(app_idx));
+	key = l_queue_find(rmt->app_keys, match_key,
+						L_UINT_TO_PTR(app_idx));
+	key->updated = update;
+
+	if (save)
+		return mesh_db_node_app_key_update(addr, app_idx, update);
+	else
+		return true;
+}
+
+void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx)
+{
+	struct remote_node *rmt;
+	struct remote_key *key;
+	const struct l_queue_entry *l;
+
+	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
+	if (!rmt)
+		return;
+
+	if (!remote_update_net_key(addr, net_idx, false, true))
+		return;
+
+	l = l_queue_get_entries(rmt->app_keys);
+
+	for (; l; l = l->next) {
+		key = l->data;
+
+		if (net_idx != keys_get_bound_key(key->idx))
+			continue;
+
+		key->updated = false;
+
+		mesh_db_node_app_key_update(addr, key->idx, false);
+	}
+
 }
 
 uint16_t remote_get_subnet_idx(uint16_t addr)
 {
 	struct remote_node *rmt;
-	uint32_t net_idx;
+	struct remote_key *key;
 
 	rmt = l_queue_find(nodes, match_node_addr, L_UINT_TO_PTR(addr));
 
 	if (!rmt || l_queue_isempty(rmt->net_keys))
 		return NET_IDX_INVALID;
 
-	net_idx = L_PTR_TO_UINT(l_queue_peek_head(rmt->net_keys));
+	key = l_queue_peek_head(rmt->net_keys);
 
-	return (uint16_t) net_idx;
+	return key->idx;
 }
 
-static void print_key(void *key, void *user_data)
+static void print_key(void *data, void *user_data)
 {
-	uint16_t idx = L_PTR_TO_UINT(key);
+	struct remote_key *key = data;
 
-	bt_shell_printf("%u (0x%3.3x), ", idx, idx);
+	bt_shell_printf("%u (0x%3.3x) %s, ", key->idx, key->idx,
+						key->updated ? ", updated":"");
 }
 
 static void print_model(void *model, void *user_data)
diff --git a/tools/mesh/remote.h b/tools/mesh/remote.h
index 8ecb097ae..74747689a 100644
--- a/tools/mesh/remote.h
+++ b/tools/mesh/remote.h
@@ -16,10 +16,15 @@ bool remote_set_model(uint16_t unicast, uint8_t ele_idx, uint32_t mod_id,
 void remote_add_rejected_address(uint16_t addr, uint32_t iv_index, bool save);
 void remote_clear_rejected_addresses(uint32_t iv_index);
 uint16_t remote_get_next_unicast(uint16_t low, uint16_t high, uint8_t ele_cnt);
-bool remote_add_net_key(uint16_t addr, uint16_t net_idx);
+bool remote_add_net_key(uint16_t addr, uint16_t net_idx, bool save);
 bool remote_del_net_key(uint16_t addr, uint16_t net_idx);
-bool remote_add_app_key(uint16_t addr, uint16_t app_idx);
+bool remote_update_net_key(uint16_t addr, uint16_t net_idx, bool update,
+								bool save);
+bool remote_add_app_key(uint16_t addr, uint16_t app_idx, bool save);
 bool remote_del_app_key(uint16_t addr, uint16_t app_idx);
+bool remote_update_app_key(uint16_t addr, uint16_t app_idx, bool update,
+								bool save);
+void remote_finish_key_refresh(uint16_t addr, uint16_t net_idx);
 uint16_t remote_get_subnet_idx(uint16_t addr);
 void remote_print_node(uint16_t addr);
 void remote_print_all(void);
