diff --git a/slurm/slurm.h.in b/slurm/slurm.h.in
index 038c1839de999a0f1eb6cb744dec2429e22e4d17..605de6caa85c97e77bafd7c038c89a25b4a66bff 100644
--- a/slurm/slurm.h.in
+++ b/slurm/slurm.h.in
@@ -2392,18 +2392,19 @@ typedef struct trigger_info_msg {
 /* Individual license information
  */
 typedef struct slurm_license_info {
-	char *feature;       /* feature name */
+	char *name;          /* license name */
 	uint32_t total;      /* total number of available licenses */
 	uint32_t in_use;     /* number of license in use */
 	uint32_t available;  /* number of available license */
-	uint32_t cluster;    /* non-zero if cluster license */
+	uint8_t remote;      /* non-zero if remote license (not
+			      * defined in slurm.conf) */
 } slurm_license_info_t;
 
 /* License information array as returned by the controller.
  */
 typedef struct license_info_msg {
 	time_t last_update;
-	uint32_t num_features;
+	uint32_t num_lic;
 	slurm_license_info_t *lic_array;
 } license_info_msg_t;
 
diff --git a/slurm/slurmdb.h b/slurm/slurmdb.h
index d883dd7456ff5915e0b58d8334cfdf497113e636..1e4c2688a8d44387e308dc5a63b5b9eb74e7bc26 100644
--- a/slurm/slurmdb.h
+++ b/slurm/slurmdb.h
@@ -112,7 +112,8 @@ typedef enum {
 } slurmdb_report_time_format_t;
 
 typedef enum {
-	SLURMDB_RESOURCE_LICENSE = 1,
+	SLURMDB_RESOURCE_NOTSET,
+	SLURMDB_RESOURCE_LICENSE,
 } slurmdb_resource_type_t;
 
 typedef enum {
diff --git a/src/common/assoc_mgr.c b/src/common/assoc_mgr.c
index 41ecdc7ee7198c615a8bba3bf936716873de4421..cd6be8685d2d7b72c73cb1b956c20791b05af412 100644
--- a/src/common/assoc_mgr.c
+++ b/src/common/assoc_mgr.c
@@ -62,9 +62,13 @@ static char *assoc_mgr_cluster_name = NULL;
 static int setup_children = 0;
 static assoc_mgr_lock_flags_t assoc_mgr_locks;
 
+void (*add_license_notify) (slurmdb_clus_res_rec_t *rec) = NULL;
 void (*remove_assoc_notify) (slurmdb_association_rec_t *rec) = NULL;
+void (*remove_license_notify) (slurmdb_clus_res_rec_t *rec) = NULL;
 void (*remove_qos_notify) (slurmdb_qos_rec_t *rec) = NULL;
+void (*sync_license_notify) (List clus_res_list) = NULL;
 void (*update_assoc_notify) (slurmdb_association_rec_t *rec) = NULL;
+void (*update_license_notify) (slurmdb_clus_res_rec_t *rec) = NULL;
 void (*update_qos_notify) (slurmdb_qos_rec_t *rec) = NULL;
 void (*update_resvs) () = NULL;
 
@@ -665,6 +669,14 @@ static int _post_qos_list(List qos_list)
 	return SLURM_SUCCESS;
 }
 
+static int _post_clus_res_list(List clus_res_list)
+{
+	if (sync_license_notify)
+		sync_license_notify(clus_res_list);
+
+	return SLURM_SUCCESS;
+}
+
 static int _get_assoc_mgr_association_list(void *db_conn, int enforce)
 {
 	slurmdb_association_cond_t assoc_q;
@@ -729,7 +741,7 @@ static int _get_assoc_mgr_clus_res_list(void *db_conn, int enforce)
 	if (assoc_mgr_clus_res_list)
 		list_destroy(assoc_mgr_clus_res_list);
 	assoc_mgr_clus_res_list =
-	   acct_storage_g_get_clus_res(db_conn, uid, NULL);
+		acct_storage_g_get_clus_res(db_conn, uid, NULL);
 
 	if (!assoc_mgr_clus_res_list) {
 		assoc_mgr_unlock(&locks);
@@ -742,7 +754,7 @@ static int _get_assoc_mgr_clus_res_list(void *db_conn, int enforce)
 		}
 	}
 
-//	_post_clus_res_list(assoc_mgr_clus_res_list);
+	_post_clus_res_list(assoc_mgr_clus_res_list);
 
 	assoc_mgr_unlock(&locks);
 	return SLURM_SUCCESS;
@@ -961,7 +973,7 @@ static int _refresh_assoc_mgr_clus_res_list(void *db_conn, int enforce)
 		      "no new list given back keeping cached one.");
 		return SLURM_ERROR;
 	}
-//	_post_clus_res_list(current_clus_res);
+	_post_clus_res_list(current_clus_res);
 
 	assoc_mgr_lock(&locks);
 
@@ -1170,12 +1182,20 @@ extern int assoc_mgr_init(void *db_conn, assoc_init_args_t *args,
 		cache_level = args->cache_level;
 		enforce = args->enforce;
 
+		if (args->add_license_notify)
+			add_license_notify = args->add_license_notify;
 		if (args->remove_assoc_notify)
 			remove_assoc_notify = args->remove_assoc_notify;
+		if (args->remove_license_notify)
+			remove_license_notify = args->remove_license_notify;
 		if (args->remove_qos_notify)
 			remove_qos_notify = args->remove_qos_notify;
+		if (args->sync_license_notify)
+			sync_license_notify = args->sync_license_notify;
 		if (args->update_assoc_notify)
 			update_assoc_notify = args->update_assoc_notify;
+		if (args->update_license_notify)
+			update_license_notify = args->update_license_notify;
 		if (args->update_qos_notify)
 			update_qos_notify = args->update_qos_notify;
 		if (args->update_resvs)
@@ -3313,6 +3333,16 @@ extern int assoc_mgr_update_clus_res(slurmdb_update_object_t *update)
 			}
 
 			list_append(assoc_mgr_clus_res_list, object);
+			switch (object->res_ptr->type) {
+			case SLURMDB_RESOURCE_LICENSE:
+				if (add_license_notify)
+					add_license_notify(object);
+				break;
+			default:
+				error("SLURMDB_ADD_CLUS_RES: unknown type %d",
+				      object->res_ptr->type);
+				break;
+			}
 			object = NULL;
 			break;
 		case SLURMDB_MODIFY_CLUS_RES:
@@ -3323,12 +3353,34 @@ extern int assoc_mgr_update_clus_res(slurmdb_update_object_t *update)
 
 			if (object->percent_allowed != NO_VAL)
 				rec->percent_allowed = object->percent_allowed;
+			switch (rec->res_ptr->type) {
+			case SLURMDB_RESOURCE_LICENSE:
+				if (update_license_notify)
+					update_license_notify(rec);
+				break;
+			default:
+				error("SLURMDB_UPDATE_CLUS_RES: "
+				      "unknown type %d",
+				      rec->res_ptr->type);
+				break;
+			}
 			break;
 		case SLURMDB_REMOVE_CLUS_RES:
 			if (!rec) {
 				//rc = SLURM_ERROR;
 				break;
 			}
+			switch (rec->res_ptr->type) {
+			case SLURMDB_RESOURCE_LICENSE:
+				if (remove_license_notify)
+					remove_license_notify(rec);
+				break;
+			default:
+				error("SLURMDB_REMOVE_CLUS_RES: "
+				      "unknown type %d",
+				      object->res_ptr->type);
+				break;
+			}
 
 			list_delete_item(itr);
 			break;
@@ -4045,6 +4097,7 @@ extern int load_assoc_mgr_state(char *state_save_location)
 			if (assoc_mgr_clus_res_list)
 				list_destroy(assoc_mgr_clus_res_list);
 			assoc_mgr_clus_res_list = msg->my_list;
+			_post_clus_res_list(assoc_mgr_clus_res_list);
 			debug("Recovered %u clus_res",
 			      list_count(assoc_mgr_clus_res_list));
 			msg->my_list = NULL;
@@ -4136,9 +4189,8 @@ extern int assoc_mgr_refresh_lists(void *db_conn, assoc_init_args_t *args)
 			return SLURM_ERROR;
 
 	if (cache_level & ASSOC_MGR_CACHE_CLUS_RES)
-info("invoking _refresh_assoc_mgr_clus_res_list");
 		if (_refresh_assoc_mgr_clus_res_list(db_conn, enforce)
-		    ==SLURM_ERROR)
+		    == SLURM_ERROR)
 			return SLURM_ERROR;
 
 	running_cache = 0;
diff --git a/src/common/assoc_mgr.h b/src/common/assoc_mgr.h
index 311c7d568e30620afc8b3d1f2860f1c2d1f3c81e..b37711880c933e501b4f95f776b9a47c6a755ce4 100644
--- a/src/common/assoc_mgr.h
+++ b/src/common/assoc_mgr.h
@@ -93,9 +93,13 @@ typedef struct {
 typedef struct {
  	uint16_t cache_level;
 	uint16_t enforce;
+	void (*add_license_notify) (slurmdb_clus_res_rec_t *rec);
  	void (*remove_assoc_notify) (slurmdb_association_rec_t *rec);
+	void (*remove_license_notify) (slurmdb_clus_res_rec_t *rec);
  	void (*remove_qos_notify) (slurmdb_qos_rec_t *rec);
+	void (*sync_license_notify) (List clus_res_list);
  	void (*update_assoc_notify) (slurmdb_association_rec_t *rec);
+	void (*update_license_notify) (slurmdb_clus_res_rec_t *rec);
  	void (*update_qos_notify) (slurmdb_qos_rec_t *rec);
 	void (*update_resvs) ();
 } assoc_init_args_t;
diff --git a/src/common/slurm_protocol_defs.c b/src/common/slurm_protocol_defs.c
index 8d6b05f232a82a2d07f9c99fb1f45e8248b2fd1c..7079880db3bae1bf03f6bb134797c87b3b696318 100644
--- a/src/common/slurm_protocol_defs.c
+++ b/src/common/slurm_protocol_defs.c
@@ -2953,8 +2953,8 @@ slurm_free_license_info_msg(license_info_msg_t *msg)
 	if (msg == NULL)
 		return;
 
-	for (cc = 0; cc < msg->num_features; cc++) {
-		xfree(msg->lic_array[cc].feature);
+	for (cc = 0; cc < msg->num_lic; cc++) {
+		xfree(msg->lic_array[cc].name);
 	}
 	xfree(msg->lic_array);
 	xfree(msg);
diff --git a/src/common/slurm_protocol_pack.c b/src/common/slurm_protocol_pack.c
index 722f512a50a3f67fd79a5ca86da395ca2ddbfe39..ad880941a309afb93f5269693e754f48c4833808 100644
--- a/src/common/slurm_protocol_pack.c
+++ b/src/common/slurm_protocol_pack.c
@@ -11722,23 +11722,24 @@ _unpack_license_info_msg(license_info_msg_t **msg,
 	 */
 	if (protocol_version >= SLURM_14_03_PROTOCOL_VERSION) {
 
-		safe_unpack32(&((*msg)->num_features), buffer);
+		safe_unpack32(&((*msg)->num_lic), buffer);
 		safe_unpack_time(&((*msg)->last_update), buffer);
 
 		(*msg)->lic_array = xmalloc(sizeof(slurm_license_info_t)
-		                            * (*msg)->num_features);
+		                            * (*msg)->num_lic);
 
 		/* Decode individual license data.
 		 */
-		for (i = 0; i < (*msg)->num_features; i++) {
-
-			safe_unpackstr_xmalloc(&((*msg)->lic_array[i]).feature, &zz, buffer);
+		for (i = 0; i < (*msg)->num_lic; i++) {
+			safe_unpackstr_xmalloc(&((*msg)->lic_array[i]).name,
+					       &zz, buffer);
 			safe_unpack32(&((*msg)->lic_array[i]).total, buffer);
 			safe_unpack32(&((*msg)->lic_array[i]).in_use, buffer);
-			(*msg)->lic_array[i].available
-				= (*msg)->lic_array[i].total - (*msg)->lic_array[i].in_use;
+			(*msg)->lic_array[i].available =
+				(*msg)->lic_array[i].total -
+				(*msg)->lic_array[i].in_use;
 			xassert((*msg)->lic_array[i].available >= 0);
-			safe_unpack32(&((*msg)->lic_array[i]).cluster, buffer);
+			safe_unpack8(&((*msg)->lic_array[i]).remote, buffer);
 		}
 
 	} else {
diff --git a/src/scontrol/info_lics.c b/src/scontrol/info_lics.c
index 906c792a8e6b6ee0a6087fd2e3a6303cce78d3de..a027002013af85a9cdfea6a96a6b0b9a4c9cf691 100644
--- a/src/scontrol/info_lics.c
+++ b/src/scontrol/info_lics.c
@@ -40,8 +40,7 @@
 
 #include "scontrol.h"
 
-static void print_license_info(const char *,
-                               struct license_info_msg *);
+static void _print_license_info(const char *, license_info_msg_t *);
 
 /* scontrol_print_licenses()
  *
@@ -50,10 +49,10 @@ static void print_license_info(const char *,
  *
  */
 void
-scontrol_print_licenses(const char *feature)
+scontrol_print_licenses(const char *name)
 {
 	int cc;
-	struct license_info_msg *msg;
+	license_info_msg_t *msg;
 	uint16_t show_flags;
 	static time_t last_update;
 
@@ -73,7 +72,7 @@ scontrol_print_licenses(const char *feature)
 	last_update = time(NULL);
 	/* print the info
 	 */
-	print_license_info(feature, msg);
+	_print_license_info(name, msg);
 
 	/* free at last
 	 */
@@ -82,33 +81,30 @@ scontrol_print_licenses(const char *feature)
 	return;
 }
 
-/* print_license_info()
+/* _print_license_info()
  *
  * Print the license information.
  */
-static void
-print_license_info(const char *feature, struct license_info_msg *msg)
+static void _print_license_info(const char *name, license_info_msg_t *msg)
 {
 	int cc;
 
-	if (msg->num_features == 0) {
-		printf("No licenses configured in SLURM.\n");
+	if (!msg->num_lic) {
+		printf("No licenses configured in Slurm.\n");
 		return;
 	}
 
-	for (cc = 0; cc < msg->num_features; cc++) {
-		if (one_liner) {
-			printf("LicenseName=%s ", msg->lic_array[cc].feature);
-			printf("Total=%d ", msg->lic_array[cc].total);
-		} else {
-			printf("LicenseName=%s\n", msg->lic_array[cc].feature);
-			printf("    Total=%d ", msg->lic_array[cc].total);
-		}
-		printf("Used=%d ", msg->lic_array[cc].in_use);
-		printf("Free=%d ", msg->lic_array[cc].available);
-		if (msg->lic_array[cc].cluster)
-			printf("Cluster=yes\n");
-		else
-			printf("Cluster=no\n");
+	for (cc = 0; cc < msg->num_lic; cc++) {
+		if (name && strcmp(msg->lic_array[cc].name, name))
+			continue;
+		printf("LicenseName=%s%sTotal=%d Used=%u Free=%u Remote=%s\n",
+		       msg->lic_array[cc].name,
+		       one_liner ? " " : "\n    ",
+		       msg->lic_array[cc].total,
+		       msg->lic_array[cc].in_use,
+		       msg->lic_array[cc].available,
+		       msg->lic_array[cc].remote ? "yes" : "no");
+		if (name)
+			break;
 	}
 }
diff --git a/src/slurmctld/controller.c b/src/slurmctld/controller.c
index 6f79ef60d97544321451fb5b884430e7311ba848..3b98b89b45fce77a8292bebbdd73f93b752598e2 100644
--- a/src/slurmctld/controller.c
+++ b/src/slurmctld/controller.c
@@ -370,11 +370,15 @@ int main(int argc, char *argv[])
 
 	memset(&assoc_init_arg, 0, sizeof(assoc_init_args_t));
 	assoc_init_arg.enforce = accounting_enforce;
-	assoc_init_arg.update_resvs = update_assocs_in_resvs;
+	assoc_init_arg.add_license_notify = license_add_remote;
 	assoc_init_arg.remove_assoc_notify = _remove_assoc;
+	assoc_init_arg.remove_license_notify = license_remove_remote;
 	assoc_init_arg.remove_qos_notify = _remove_qos;
+	assoc_init_arg.sync_license_notify = license_sync_remote;
 	assoc_init_arg.update_assoc_notify = _update_assoc;
+	assoc_init_arg.update_license_notify = license_update_remote;
 	assoc_init_arg.update_qos_notify = _update_qos;
+	assoc_init_arg.update_resvs = update_assocs_in_resvs;
 	assoc_init_arg.cache_level = ASSOC_MGR_CACHE_ASSOC |
 				     ASSOC_MGR_CACHE_USER  |
 				     ASSOC_MGR_CACHE_QOS   |
diff --git a/src/slurmctld/licenses.c b/src/slurmctld/licenses.c
index 1f3ac3466c3b47b4af0671b58c472040fe389f91..af6d045f71f01e41a35f4c03bb140cabb3394bd3 100644
--- a/src/slurmctld/licenses.c
+++ b/src/slurmctld/licenses.c
@@ -56,8 +56,7 @@
 #include "src/common/slurm_accounting_storage.h"
 
 List license_list = (List) NULL;
-List clus_license_list = (List) NULL;
-time_t last_license_update;
+time_t last_license_update = 0;
 static pthread_mutex_t license_mutex = PTHREAD_MUTEX_INITIALIZER;
 static void _pack_license(struct licenses *lic, Buf buffer, uint16_t protocol_version);
 
@@ -109,34 +108,6 @@ static int _license_find_rec(void *x, void *key)
 	return 1;
 }
 
-/* Find a slurmdb_ser_res_rec_t record by license name
- *(for use by list_find_first) */
-static int _license_find_sys_rec(void *x, void *key)
-{
-	slurmdb_ser_res_rec_t *license_entry = (slurmdb_ser_res_rec_t *) x;
-	char *name = (char *) key;
-
-	if ((license_entry->name == NULL) || (name == NULL))
-		return 0;
-	if (strcmp(license_entry->name, name))
-		return 0;
-	return 1;
-}
-
-/* Find a slurmdb_clus_res_rec_t record by license name
- *(for use by list_find_first) */
-static int _license_find_clus_rec(void *x, void *key)
-{
-	slurmdb_clus_res_rec_t *license_entry = (slurmdb_clus_res_rec_t *) x;
-	char *name = (char *) key;
-
-	if ((license_entry->res_ptr->name == NULL) || (name == NULL))
-		return 0;
-	if (strcmp(license_entry->res_ptr->name, name))
-		return 0;
-	return 1;
-}
-
 /* Given a license string, return a list of license_t records */
 static List _build_license_list(char *licenses, bool *valid)
 {
@@ -221,6 +192,21 @@ static char * _build_license_string(List license_list)
 	return licenses;
 }
 
+/* license_mutex should be locked before alling this. */
+static void _add_clus_rec_2_lic_list(slurmdb_clus_res_rec_t *rec, bool sync)
+{
+	licenses_t *license_entry = xmalloc(sizeof(licenses_t));
+	/* Should we concat the server and such here
+	 * with the name? */
+	license_entry->name = xstrdup(rec->res_ptr->name);
+	license_entry->total = ((rec->res_ptr->count *
+				 rec->percent_allowed) / 100);
+	license_entry->remote = sync ? 2 : 1;
+
+	list_push(license_list, license_entry);
+	last_license_update = time(NULL);
+}
+
 /* Get string of used license information. Caller must xfree return value */
 extern char *get_licenses_used(void)
 {
@@ -245,276 +231,6 @@ extern char *get_licenses_used(void)
 	return licenses_used;
 }
 
-/* Merge a cluster license list (built using accounting database information
- * into a license_list, preserving all previously allocated licenses.
-*/
-static List merge_license_lists(List lic_list, List clus_license_list)
-{
-	licenses_t *license, *cluster_license, *new_license;
-	ListIterator itr = NULL;
-	licenses_t *match_lic = NULL;
-	uint16_t temp;
-
-	if (!clus_license_list)
-		return lic_list;
-	if (!license_list)
-		return clus_license_list;
-	/* deal with new & potentially modified cluster licenses */
-	itr = list_iterator_create(clus_license_list);
-	while ((cluster_license = list_next(itr))){
-		match_lic = list_find_first(license_list,
-			_license_find_rec, cluster_license->name);
-
-		if (match_lic == NULL) {		/* new license */
-			new_license = xmalloc(sizeof(licenses_t));
-			new_license->name = xstrdup(cluster_license->name);
-			new_license->total = cluster_license->total;
-			new_license->used = 0;
-			new_license->cluster = 1;
-			list_push(lic_list, new_license);
-		} else if ((match_lic != NULL)
-			   && cluster_license->cluster == 1) {
-			match_lic->total = cluster_license->total;
-		}
-	}
-	list_iterator_destroy(itr);
-
-	/* now deal with deleted cluster licenses */
-	itr = list_iterator_create(license_list);
-	while ((license = (licenses_t *) list_next(itr))) {
-		match_lic = list_find_first(clus_license_list,
-			_license_find_rec, license->name);
-
-		if ((match_lic == NULL) && (license->cluster == 1)) {
-			temp = list_delete_item(itr);
-			if (!temp)
-				return NULL;
-		}
-	}
-	list_iterator_destroy(itr);
-	return lic_list;
-}
-
-/* update clus_license_list & license_list for a modified system license */
-static int _modify_ser_lic(List clus_license_list, List clus_rec_list,
-			    slurmdb_update_object_t *update_obj)
-{
-	ListIterator itr = NULL;
-	slurmdb_ser_res_rec_t *match_sys_rec = NULL;
-	slurmdb_clus_res_rec_t *match_clus_rec = NULL;
-	licenses_t *license;
-	uint16_t rc = SLURM_SUCCESS;
-
-	itr = list_iterator_create(clus_license_list);
-	while ((license = list_next(itr))) {
-		match_sys_rec = list_find_first(update_obj->objects,
-				_license_find_sys_rec, license->name);
-		if (match_sys_rec) {
-			match_clus_rec = list_find_first(clus_rec_list,
-			_license_find_clus_rec, license->name);
-			if (match_clus_rec) {
-				license->total =
-				 ((match_sys_rec->count *
-				   match_clus_rec->percent_allowed) / 100);
-			}
-		}
-	}
-	list_iterator_destroy(itr);
-	return rc;
-}
-
-/* update clus_license_list to add a cluster license */
-static int _add_clus_lic(List clus_license_list,
-			  slurmdb_update_object_t *update_obj)
-{
-	ListIterator itr = NULL;
-	slurmdb_clus_res_rec_t *clus_rec = NULL;
-	licenses_t *match_lic = NULL;
-	licenses_t *new_license;
-	uint16_t rc = SLURM_SUCCESS;
-	char *cluster_name = NULL;
-
-	cluster_name = slurm_get_cluster_name();
-	itr = list_iterator_create(update_obj->objects);
-	while ((clus_rec = list_next(itr))) {
-		if (!strstr(clus_rec->cluster, cluster_name) ||
-		    clus_rec->res_ptr->type != SLURMDB_RESOURCE_LICENSE)
-			continue;
-		match_lic = list_find_first(clus_license_list,
-			_license_find_rec, clus_rec->res_ptr->name);
-
-		if (match_lic == NULL) {
-			new_license = xmalloc(sizeof(licenses_t));
-			new_license->name = xstrdup(clus_rec->res_ptr->name);
-			new_license->total =
-			((clus_rec->res_ptr->count *
-			  clus_rec->percent_allowed) / 100);
-			new_license->used = 0;
-			new_license->cluster = 1;
-			list_push(clus_license_list, new_license);
-			slurmdb_clus_res_rec_t *new_rec =
-					xmalloc(sizeof(slurmdb_clus_res_rec_t));
-			slurmdb_init_clus_res_rec(new_rec, 0);
-			new_rec->res_ptr = xmalloc(sizeof(
-					   slurmdb_ser_res_rec_t));
-			slurmdb_init_ser_res_rec(new_rec->res_ptr, 0);
-			new_rec->res_ptr->description =
-			   xstrdup(clus_rec->res_ptr->description);
-			new_rec->res_ptr->id = clus_rec->res_ptr->id;
-			new_rec->res_ptr->name =
-			   xstrdup(clus_rec->res_ptr->name);
-			new_rec->res_ptr->count = clus_rec->res_ptr->count;
-			new_rec->res_ptr->type = clus_rec->res_ptr->type;
-			new_rec->res_ptr->manager =
-			   xstrdup(clus_rec->res_ptr->manager);
-			new_rec->res_ptr->server =
-			   xstrdup(clus_rec->res_ptr->server);
-			new_rec->cluster = xstrdup(clus_rec->cluster);
-			new_rec->percent_allowed = clus_rec->percent_allowed;
-			list_append(assoc_mgr_clus_res_list, new_rec);
-		} else {
-			error("cluster_resource_list already contains"
-			       " this cluster license %s",
-			       clus_rec->res_ptr->name);
-			rc = SLURM_ERROR;
-			break;
-		}
-	}
-	xfree(cluster_name);
-	list_iterator_destroy(itr);
-	return rc;
-}
-
-/* update clus_license_list for a modified cluster license */
-static int _modify_clus_lic(List clus_license_list,
-			     slurmdb_update_object_t *update_obj)
-{
-	ListIterator itr = NULL;
-	ListIterator itr2 = NULL;
-	slurmdb_clus_res_rec_t *clus_rec = NULL;
-	slurmdb_clus_res_rec_t *assoc_mgr_rec = NULL;
-	licenses_t *match_lic = NULL;
-	uint16_t rc = SLURM_SUCCESS;
-	char *cluster_name = NULL;
-
-	cluster_name = slurm_get_cluster_name();
-	itr = list_iterator_create(update_obj->objects);
-	itr2 = list_iterator_create(assoc_mgr_clus_res_list);
-	while ((clus_rec = list_next(itr))) {
-		if (!strstr(clus_rec->cluster, cluster_name) ||
-		    clus_rec->res_ptr->type != SLURMDB_RESOURCE_LICENSE)
-			continue;
-		match_lic = list_find_first(clus_license_list,
-			    _license_find_rec, clus_rec->res_ptr->name);
-		if (match_lic) {
-			match_lic->total =
-			((clus_rec->res_ptr->count *
-			  clus_rec->percent_allowed) / 100);
-			while ((assoc_mgr_rec = list_next(itr2))) {
-				if (strstr(clus_rec->res_ptr->name,
-					assoc_mgr_rec->res_ptr->name)) {
-						assoc_mgr_rec->percent_allowed =
-						   clus_rec->percent_allowed;
-					}
-			}
-			list_iterator_reset(itr2);
-		} else {
-			error("cluster_license_list doesn't contain %s",
-			       clus_rec->res_ptr->name);
-			rc = SLURM_ERROR;
-			break;
-		}
-	}
-	xfree(cluster_name);
-	list_iterator_destroy(itr);
-	list_iterator_destroy(itr2);
-	return rc;
-}
-
-/* update clus_license_list for a removed cluster license */
-static int _remove_clus_lic(List clus_license_list,
-			     slurmdb_update_object_t *update_obj)
-{
-	ListIterator itr = NULL;
-	ListIterator itr2 = NULL;
-	ListIterator itr3 = NULL;
-	slurmdb_clus_res_rec_t *clus_rec = NULL;
-	slurmdb_clus_res_rec_t *assoc_mgr_rec = NULL;
-	licenses_t *license;
-	uint16_t temp;
-	uint16_t rc = SLURM_SUCCESS;
-	char *cluster_name = NULL;
-
-	cluster_name = slurm_get_cluster_name();
-	itr = list_iterator_create(update_obj->objects);
-	itr2 = list_iterator_create(clus_license_list);
-	itr3 = list_iterator_create(assoc_mgr_clus_res_list);
-	while ((clus_rec = list_next(itr))) {
-		if (!strstr(clus_rec->cluster, cluster_name) ||
-		    clus_rec->res_ptr->type != SLURMDB_RESOURCE_LICENSE)
-			continue;
-		while ((license = list_next(itr2))) {
-			if (strstr(clus_rec->res_ptr->name, license->name)) {
-				temp = list_delete_item(itr2);
-				if (!temp) {
-					error("clus_license_list removal"
-					      "problem for %s", license->name);
-					rc = SLURM_ERROR;
-					break;
-				}
-				while ((assoc_mgr_rec = list_next(itr3))) {
-					if (strstr(clus_rec->res_ptr->name,
-						assoc_mgr_rec->res_ptr->name)) {
-						temp = list_delete_item(itr3);
-						if (!temp) {
-							error("assoc_mgr_clus_"
-							"res_list removal"
-							"problem for %s",
-							license->name);
-							rc = SLURM_ERROR;
-							break;
-						}
-					}
-				}
-				list_iterator_reset(itr3);
-			}
-		}
-		list_iterator_reset(itr2);
-	}
-	xfree(cluster_name);
-	list_iterator_destroy(itr);
-	list_iterator_destroy(itr2);
-	list_iterator_destroy(itr3);
-	return rc;
-}
-
-/* create a list of license_t records from a list of clus_res_rec_t
- * records
- */
-static List _clus_license_init(List clus_rec_list)
-{
-	List clus_license_list = NULL;
-	ListIterator itr = NULL;
-	slurmdb_clus_res_rec_t *clus_rec = NULL;
-	licenses_t *license;
-
-	if (!clus_rec_list) {
-		return NULL;
-	}
-	clus_license_list = list_create(license_free_rec);
-	itr = list_iterator_create(clus_rec_list );
-	while ((clus_rec = list_next(itr))) {
-		license = xmalloc(sizeof(licenses_t));
-		license->name = xstrdup(clus_rec->res_ptr->name);
-		license->total =
-		 ((clus_rec->res_ptr->count * clus_rec->percent_allowed) / 100);
-		license->used = 0;
-		license->cluster = 1;
-		list_push(clus_license_list, license);
-	}
-	list_iterator_destroy(itr);
-	return clus_license_list;
-}
 
 /* Initialize licenses on this system based upon slurm.conf
  * and information in the accounting database/
@@ -533,122 +249,250 @@ extern int license_init(char *licenses)
 	if (!valid)
 		fatal("Invalid configured licenses: %s", licenses);
 
-	if (assoc_mgr_clus_res_list) {
-		clus_license_list = _clus_license_init(assoc_mgr_clus_res_list);
-		license_list = merge_license_lists(license_list,
-			       clus_license_list);
-	}
-
 	_licenses_print("init_license", license_list, 0);
 	slurm_mutex_unlock(&license_mutex);
-
 	return SLURM_SUCCESS;
 }
 
-/* Update the cluster license list for this system.
- * Preserve all previously allocated licenses */
-static List _clus_license_list_update(slurmdb_update_object_t *update_obj)
+/* Update licenses on this system based upon slurm.conf.
+* Preserve all previously allocated licenses */
+extern int license_update(char *licenses)
 {
-	uint16_t type;
-	uint16_t rc = SLURM_SUCCESS;
+        ListIterator iter;
+        licenses_t *license_entry, *match;
+        List new_list;
+        bool valid;
+
+        new_list = _build_license_list(licenses, &valid);
+        if (!valid)
+                fatal("Invalid configured licenses: %s", licenses);
+
+        slurm_mutex_lock(&license_mutex);
+        if (!license_list) {        /* no licenses before now */
+                license_list = new_list;
+                slurm_mutex_unlock(&license_mutex);
+                return SLURM_SUCCESS;
+        }
+
+        iter = list_iterator_create(license_list);
+        while ((license_entry = (licenses_t *) list_next(iter))) {
+		/* Always add the remote ones, since we handle those
+		   else where. */
+		if (license_entry->remote) {
+			list_remove(iter);
+			if (!new_list)
+				new_list = list_create(license_free_rec);
+			list_append(new_list, license_entry);
+			continue;
+		}
+		if (new_list)
+			match = list_find_first(new_list, _license_find_rec,
+						license_entry->name);
+		else
+			match = NULL;
 
-	if (!clus_license_list) {
-		if (assoc_mgr_clus_res_list)
-			clus_license_list =
-			   _clus_license_init(assoc_mgr_clus_res_list);
+                if (!match) {
+                        info("license %s removed with %u in use",
+                         license_entry->name, license_entry->used);
+                } else {
+                        match->used = license_entry->used;
+                        if (match->used > match->total) {
+                                info("license %s count decreased",
+                                 match->name);
+                        }
+                }
+        }
+        list_iterator_destroy(iter);
+
+        list_destroy(license_list);
+        license_list = new_list;
+        _licenses_print("update_license", license_list, 0);
+        slurm_mutex_unlock(&license_mutex);
+        return SLURM_SUCCESS;
+}
+
+extern void license_add_remote(slurmdb_clus_res_rec_t *rec)
+{
+	licenses_t *license_entry;
+	ListIterator iter;
+
+	xassert(rec);
+	xassert(rec->res_ptr);
+	xassert(rec->res_ptr->type == SLURMDB_RESOURCE_LICENSE);
+
+	slurm_mutex_lock(&license_mutex);
+	if (!license_list) {
+		/* If last_license_update then init already ran and we
+		 * don't have any licenses defined in the slurm.conf
+		 * so make the license_list.
+		 */
+		xassert(last_license_update);
+		license_list = list_create(license_free_rec);
 	}
-	type = update_obj->type;
-	switch ( type )
-	{
-		case SLURMDB_MODIFY_SER_RES :
-			rc = _modify_ser_lic(clus_license_list,
-					     assoc_mgr_clus_res_list,
-					     update_obj);
-			break;
-		case SLURMDB_ADD_SER_RES :
-		case SLURMDB_REMOVE_SER_RES :
-			break;
-		case SLURMDB_ADD_CLUS_RES :
-			rc = _add_clus_lic(clus_license_list, update_obj);
-			break;
-		case SLURMDB_MODIFY_CLUS_RES :
-			rc = _modify_clus_lic(clus_license_list, update_obj);
-			break;
-		case SLURMDB_REMOVE_CLUS_RES :
-			rc = _remove_clus_lic(clus_license_list, update_obj);
+
+	iter = list_iterator_create(license_list);
+	while ((license_entry = list_next(iter))) {
+		/* Should we look at all licenses not just
+		 * remote ones? */
+		if (!license_entry->remote)
+			continue;
+		if (!strcmp(license_entry->name, rec->res_ptr->name)) {
+			error("license_add_remote: license %s "
+			      "already exists!", rec->res_ptr->name);
 			break;
+		}
 	}
-	if (rc != SLURM_SUCCESS) {
-		error("problem updating clus_license_list");
-		return NULL;
-	}
+	list_iterator_destroy(iter);
+
+	if (!license_entry)
+		_add_clus_rec_2_lic_list(rec, 0);
 
-	return clus_license_list;
+	slurm_mutex_unlock(&license_mutex);
 }
 
-/* Update licenses on this system based upon slurm.conf.
- * Preserve all previously allocated licenses */
-extern int license_update(char *licenses)
+extern void license_update_remote(slurmdb_clus_res_rec_t *rec)
 {
+	licenses_t *license_entry;
 	ListIterator iter;
-	licenses_t *license_entry, *match;
-	List new_list;
-	bool valid;
 
-	new_list = _build_license_list(licenses, &valid);
-	if (!valid)
-		fatal("Invalid configured licenses: %s", licenses);
+	xassert(rec);
+	xassert(rec->res_ptr);
+	xassert(rec->res_ptr->type == SLURMDB_RESOURCE_LICENSE);
 
 	slurm_mutex_lock(&license_mutex);
-	if (!license_list) {	/* no licenses before now */
-		license_list = new_list;
-		slurm_mutex_unlock(&license_mutex);
-		return SLURM_SUCCESS;
+	if (!license_list) {
+		/* If last_license_update then init already ran and we
+		 * don't have any licenses defined in the slurm.conf
+		 * so make the license_list.
+		 */
+		xassert(last_license_update);
+		license_list = list_create(license_free_rec);
 	}
 
 	iter = list_iterator_create(license_list);
-	while ((license_entry = (licenses_t *) list_next(iter))) {
-		match = list_find_first(new_list, _license_find_rec,
-			license_entry->name);
-		if (!match) {
-			info("license %s removed with %u in use",
-			     license_entry->name, license_entry->used);
-		} else {
-			match->used = license_entry->used;
-			match->cluster = 0;
-			if (match->used > match->total) {
+	while ((license_entry = list_next(iter))) {
+		/* Should we look at all licenses not just
+		 * remote ones? */
+		if (!license_entry->remote)
+			continue;
+		if (!strcmp(license_entry->name, rec->res_ptr->name)) {
+			license_entry->total =
+				((rec->res_ptr->count *
+				  rec->percent_allowed) / 100);
+			if (license_entry->used >
+			    license_entry->total) {
 				info("license %s count decreased",
-				     match->name);
+				     license_entry->name);
 			}
+			last_license_update = time(NULL);
+			break;
 		}
 	}
 	list_iterator_destroy(iter);
+	if (!license_entry) {
+		debug("license_update_remote: License '%s' not found, adding",
+		      rec->res_ptr->name);
+		_add_clus_rec_2_lic_list(rec, 0);
+	}
+	slurm_mutex_unlock(&license_mutex);
+}
+
+extern void license_remove_remote(slurmdb_clus_res_rec_t *rec)
+{
+	licenses_t *license_entry;
+	ListIterator iter;
+
+	xassert(rec);
+	xassert(rec->res_ptr);
+	xassert(rec->res_ptr->type == SLURMDB_RESOURCE_LICENSE);
 
-	list_destroy(license_list);
-	license_list = new_list;
-	_licenses_print("update_license", license_list, 0);
+	slurm_mutex_lock(&license_mutex);
+	if (!license_list) {
+		xassert(last_license_update);
+		license_list = list_create(license_free_rec);
+	}
+
+	iter = list_iterator_create(license_list);
+	while ((license_entry = list_next(iter))) {
+		/* Should we look at all licenses not just
+		 * remote ones? */
+		if (!license_entry->remote)
+			continue;
+		if (!strcmp(license_entry->name, rec->res_ptr->name)) {
+			info("license_remove_remote: license %s "
+			     "removed with %u in use",
+			     license_entry->name, license_entry->used);
+			list_delete_item(iter);
+			last_license_update = time(NULL);
+			break;
+		}
+	}
+	list_iterator_destroy(iter);
+	if (!license_entry)
+		error("license_remote_remote: License '%s' not found",
+		      rec->res_ptr->name);
 	slurm_mutex_unlock(&license_mutex);
-	return SLURM_SUCCESS;
 }
 
-/* Update cluster licenses on this system based upon accounting database.
- * Preserve all previously allocated licenses */
-extern int cluster_license_update(slurmdb_update_object_t *update_obj)
+extern void license_sync_remote(List clus_res_list)
 {
-	List clus_license_list;
+	slurmdb_clus_res_rec_t *rec = NULL;
+	licenses_t *license_entry;
+	ListIterator iter;
 
 	slurm_mutex_lock(&license_mutex);
-	clus_license_list = _clus_license_list_update(update_obj);
+	if (clus_res_list && !license_list) {
+		xassert(last_license_update);
+		license_list = list_create(license_free_rec);
+	}
 
-	if (!license_list) {	/* no licenses before now */
-		license_list = clus_license_list;
-	} else {
-		if (clus_license_list)
-			license_list =
-			  merge_license_lists(license_list, clus_license_list);
+	iter = list_iterator_create(license_list);
+	if (clus_res_list) {
+		ListIterator iter2 = list_iterator_create(clus_res_list);
+		while ((rec = list_next(iter2))) {
+			if (rec->res_ptr->type != SLURMDB_RESOURCE_LICENSE)
+				continue;
+			while ((license_entry = list_next(iter))) {
+				if (!license_entry->remote)
+					continue;
+				if (!strcmp(license_entry->name,
+					    rec->res_ptr->name)) {
+					license_entry->remote = 2;
+					license_entry->total =
+						((rec->res_ptr->count *
+						  rec->percent_allowed) / 100);
+					if (license_entry->used >
+					    license_entry->total) {
+						info("license %s count "
+						     "decreased",
+						     license_entry->name);
+					}
+					last_license_update = time(NULL);
+					break;
+				}
+			}
+			if (!license_entry)
+				_add_clus_rec_2_lic_list(rec, 1);
+			list_iterator_reset(iter);
+		}
+		list_iterator_destroy(iter2);
+	}
+
+	while ((license_entry = list_next(iter))) {
+		if (!license_entry->remote)
+			continue;
+		else if (license_entry->remote == 1) {
+			info("license_remove_remote: license %s "
+			     "removed with %u in use",
+			     license_entry->name, license_entry->used);
+			list_delete_item(iter);
+			last_license_update = time(NULL);
+		} else if (license_entry->remote == 2)
+			license_entry->remote = 1;
 	}
+	list_iterator_destroy(iter);
+
 	slurm_mutex_unlock(&license_mutex);
-	return SLURM_SUCCESS;
 }
 
 /* Free memory associated with licenses on this system */
@@ -937,9 +781,7 @@ get_all_license_info(char **buffer_ptr,
 	pack_time(now, buffer);
 
 	slurm_mutex_lock(&license_mutex);
-
 	if (license_list) {
-
 		iter = list_iterator_create(license_list);
 		while ((lic_entry = list_next(iter))) {
 			/* Now encode the license data structure.
@@ -971,7 +813,7 @@ get_all_license_info(char **buffer_ptr,
  *	char *		name;
  *	uint32_t	total;
  *	uint32_t	used;
- *	uint32_t	cluster;
+ *	uint8_t 	remote;
  *
  */
 static void
@@ -981,7 +823,7 @@ _pack_license(struct licenses *lic, Buf buffer, uint16_t protocol_version)
 		packstr(lic->name, buffer);
 		pack32(lic->total, buffer);
 		pack32(lic->used, buffer);
-		pack32(lic->cluster, buffer);
+		pack8(lic->remote, buffer);
 	} else {
 		error("\
 %s: protocol_version %hu not supported", __func__, protocol_version);
diff --git a/src/slurmctld/licenses.h b/src/slurmctld/licenses.h
index e7c867fcc59fbf625e28ee88bd485e43e05a49ac..5f2c03861c8c744871777447ae076b0178492d66 100644
--- a/src/slurmctld/licenses.h
+++ b/src/slurmctld/licenses.h
@@ -46,17 +46,13 @@ typedef struct licenses {
 	char *		name;		/* name associated with a license */
 	uint32_t	total;		/* total license configued */
 	uint32_t	used;		/* used licenses */
-	uint32_t        cluster;	/* non-zero if cluster_license */
+	uint8_t         remote;	        /* non-zero if remote (from database) */
 } licenses_t;
 
 extern List license_list;
 extern List clus_license_list;
 extern time_t last_license_update;
 
-/* Update cluster licenses on this system based upon database information.
- * Preserve all previously allocated licenses */
-extern int cluster_license_update(slurmdb_update_object_t *update_obj);
-
 /* Get string of used license information. Caller must xfree return value */
 extern char *get_licenses_used(void);
 
@@ -67,9 +63,10 @@ extern int license_init(char *licenses);
  * Preserve all previously allocated licenses */
 extern int license_update(char *licenses);
 
-/* Update cluster licenses on this system based upon accounting database.
- * Preserve all previously allocated licenses */
-extern int cluster_license_update(slurmdb_update_object_t *update_obj);
+extern void license_add_remote(slurmdb_clus_res_rec_t *rec);
+extern void license_update_remote(slurmdb_clus_res_rec_t *rec);
+extern void license_remove_remote(slurmdb_clus_res_rec_t *rec);
+extern void license_sync_remote(List clus_res_list);
 
 /* Free memory associated with licenses on this system */
 extern void license_free(void);
diff --git a/testsuite/expect/test21.31 b/testsuite/expect/test21.31
old mode 100644
new mode 100755