diff --git a/CHANGES b/CHANGES
index 74e07b6407511a81cd7acb46888b6634c36a8138..d3ca0ae8d2db68fdb84b3b7dc31b7b0ddbc17ec8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -736,6 +736,9 @@ Queue changes
   * Added a new parameter for member definition, called state_interface. This may be
     used so that a member may be called via one interface but have a different interface's
     device state reported.
+  * Added new CLI and Manager commands relating to reloading queues. From the CLI, see
+    "queue reload", "queue reset stats". Also see "manager show command QueueReload" and
+    "manager show command QueueReset."
   * New configuration option: randomperiodicannounce. If a list of periodic announcements is
     specified by the periodic-announce option, then one will be chosen randomly when it is time
     to play a periodic announcment
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 4bcf36b4c3241a3afaa45155d7f0458a75a310d9..15472cdc5af95e7b17511fa7535e534265d27a10 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -497,6 +497,13 @@ enum {
 	QUEUE_STRATEGY_WRANDOM
 };
 
+enum queue_reload_mask {
+	QUEUE_RELOAD_PARAMETERS = (1 << 0),
+	QUEUE_RELOAD_MEMBER = (1 << 1),
+	QUEUE_RELOAD_RULES = (1 << 2),
+	QUEUE_RESET_STATS = (1 << 3),
+};
+
 static const struct strategy {
 	int strategy;
 	const char *name;
@@ -544,9 +551,6 @@ static const char *pm_family = "Queue/PersistentMembers";
 /* The maximum length of each persistent member queue database entry */
 #define PM_MAX_LEN 8192
 
-/*! \brief queues.conf [general] option */
-static int queue_keep_stats = 0;
-
 /*! \brief queues.conf [general] option */
 static int queue_persistent_members = 0;
 
@@ -1185,7 +1189,6 @@ static void init_queue(struct call_queue *q)
 		else
 			q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
 	}
-	q->membercount = 0;
 	q->found = 1;
 
 	ast_string_field_set(q, sound_next, "queue-youarenext");
@@ -1238,7 +1241,6 @@ static int insert_penaltychange (const char *list_name, const char *content, con
 	int penaltychangetime, inserted = 0;
 
 	if (!(rule = ast_calloc(1, sizeof(*rule)))) {
-		ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
 		return -1;
 	}
 
@@ -1511,10 +1513,6 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
 		q->memberdelay = atoi(val);
 	} else if (!strcasecmp(param, "weight")) {
 		q->weight = atoi(val);
-		if (q->weight)
-			use_weight++;
-		/* With Realtime queues, if the last queue using weights is deleted in realtime,
-		   we will not see any effect on use_weight until next reload. */
 	} else if (!strcasecmp(param, "timeoutrestart")) {
 		q->timeoutrestart = ast_true(val);
 	} else if (!strcasecmp(param, "defaultrule")) {
@@ -1708,6 +1706,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
 		ao2_lock(q);
 		clear_queue(q);
 		q->realtime = 1;
+		q->membercount = 0;
 		/*Before we initialize the queue, we need to set the strategy, so that linear strategy
 		 * will allocate the members properly
 		 */
@@ -1789,6 +1788,7 @@ static struct call_queue *load_realtime_queue(const char *queuename)
 	struct call_queue *q = NULL, tmpq = {
 		.name = queuename,	
 	};
+	int prev_weight = 0;
 
 	/* Find the queue in the in-core list first. */
 	q = ao2_find(queues, &tmpq, OBJ_POINTER);
@@ -1812,13 +1812,27 @@ static struct call_queue *load_realtime_queue(const char *queuename)
 				return NULL;
 			}
 		}
+		if (q) {
+			prev_weight = q->weight ? 1 : 0;
+		}
 
 		ao2_lock(queues);
+
 		q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-		if (member_config)
+		if (member_config) {
 			ast_config_destroy(member_config);
-		if (queue_vars)
+		}
+		if (queue_vars) {
 			ast_variables_destroy(queue_vars);
+		}
+		/* update the use_weight value if the queue's has gained or lost a weight */ 
+		if (!q->weight && prev_weight) {
+			ast_atomic_fetchadd_int(&use_weight, -1);
+		}
+		if (q->weight && !prev_weight) {
+			ast_atomic_fetchadd_int(&use_weight, +1);
+		}
+		/* Other cases will end up with the proper value for use_weight */
 		ao2_unlock(queues);
 
 	} else {
@@ -5473,6 +5487,12 @@ static struct ast_custom_function queuememberpenalty_function = {
 	.write = queue_function_memberpenalty_write,
 };
 
+/*! \brief Reload the rules defined in queuerules.conf
+ *
+ * \param reload If 1, then only process queuerules.conf if the file
+ * has changed since the last time we inspected it.
+ * \return Always returns AST_MODULE_LOAD_SUCCESS
+ */
 static int reload_queue_rules(int reload)
 {
 	struct ast_config *cfg;
@@ -5484,59 +5504,80 @@ static int reload_queue_rules(int reload)
 	
 	if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
 		ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
+		return AST_MODULE_LOAD_SUCCESS;
 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
 		ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
 		return AST_MODULE_LOAD_SUCCESS;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
 		return AST_MODULE_LOAD_SUCCESS;
-	} else {
-		AST_LIST_LOCK(&rule_lists);
-		while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
-			while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
-				ast_free(pr_iter);
-			ast_free(rl_iter);
-		}
-		while ((rulecat = ast_category_browse(cfg, rulecat))) {
-			if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
-				ast_log(LOG_ERROR, "Memory allocation error while loading queuerules.conf! Aborting!\n");
-				AST_LIST_UNLOCK(&rule_lists);
-				return AST_MODULE_LOAD_FAILURE;
-			} else {
-				ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
-				AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
-				for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
-					if(!strcasecmp(rulevar->name, "penaltychange"))
-						insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
-					else
-						ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
-			}
+	}
+
+	AST_LIST_LOCK(&rule_lists);
+	while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
+		while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
+			ast_free(pr_iter);
+		ast_free(rl_iter);
+	}
+	while ((rulecat = ast_category_browse(cfg, rulecat))) {
+		if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
+			AST_LIST_UNLOCK(&rule_lists);
+			return AST_MODULE_LOAD_FAILURE;
+		} else {
+			ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
+			AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
+			for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
+				if(!strcasecmp(rulevar->name, "penaltychange"))
+					insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
+				else
+					ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
 		}
-		AST_LIST_UNLOCK(&rule_lists);
 	}
+	AST_LIST_UNLOCK(&rule_lists);
 
 	ast_config_destroy(cfg);
 
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
+/*! Set the global queue parameters as defined in the "general" section of queues.conf */
+static void queue_set_global_params(struct ast_config *cfg)
+{
+	const char *general_val = NULL;
+	queue_persistent_members = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
+		queue_persistent_members = ast_true(general_val);
+	autofill_default = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
+		autofill_default = ast_true(general_val);
+	montype_default = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
+		if (!strcasecmp(general_val, "mixmonitor"))
+			montype_default = 1;
+	}
+	update_cdr = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
+		update_cdr = ast_true(general_val);
+	shared_lastcall = 0;
+	if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
+		shared_lastcall = ast_true(general_val);
+}
 
-static int reload_queues(int reload)
+/*! \brief reload information pertaining to a single member
+ *
+ * This function is called when a member = line is encountered in
+ * queues.conf.
+ *
+ * \param memberdata The part after member = in the config file
+ * \param q The queue to which this member belongs
+ */
+static void reload_single_member(const char *memberdata, struct call_queue *q)
 {
-	struct call_queue *q;
-	struct ast_config *cfg;
-	char *cat, *tmp;
-	struct ast_variable *var;
+	char *membername, *interface, *state_interface, *tmp;
+	char *parse;
 	struct member *cur, *newm;
-	struct ao2_iterator mem_iter;
-	int new;
-	const char *general_val = NULL;
-	char parse[80];
-	char *interface, *state_interface;
-	char *membername = NULL;
+	struct member tmpmem;
 	int penalty;
-	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	struct ao2_iterator queue_iter;
 	AST_DECLARE_APP_ARGS(args,
 		AST_APP_ARG(interface);
 		AST_APP_ARG(penalty);
@@ -5544,195 +5585,323 @@ static int reload_queues(int reload)
 		AST_APP_ARG(state_interface);
 	);
 
-	/*First things first. Let's load queuerules.conf*/
-	if (reload_queue_rules(reload) == AST_MODULE_LOAD_FAILURE)
-		return AST_MODULE_LOAD_FAILURE;
-		
+	/* Add a new member */
+	parse = ast_strdupa(memberdata);
+				
+	AST_STANDARD_APP_ARGS(args, parse);
+
+	interface = args.interface;
+	if (!ast_strlen_zero(args.penalty)) {
+		tmp = args.penalty;
+		ast_strip(tmp);
+		penalty = atoi(tmp);
+		if (penalty < 0) {
+			penalty = 0;
+		}
+	} else {
+		penalty = 0;
+	}
+
+	if (!ast_strlen_zero(args.membername)) {
+		membername = args.membername;
+		ast_strip(membername);
+	} else {
+		membername = interface;
+	}
+
+	if (!ast_strlen_zero(args.state_interface)) {
+		state_interface = args.state_interface;
+		ast_strip(state_interface);
+	} else {
+		state_interface = interface;
+	}
+
+	/* Find the old position in the list */
+	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
+	cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
+	if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
+		ao2_link(q->members, newm);
+		ao2_ref(newm, -1);
+	}
+	newm = NULL;
+
+	if (cur) {
+		ao2_ref(cur, -1);
+	} else {
+		q->membercount++;
+	}
+}
+
+static int mark_member_dead(void *obj, void *arg, int flags)
+{
+	struct member *member = obj;
+	if (!member->dynamic) {
+		member->delme = 1;
+	}
+	return 0;
+}
+
+static int kill_dead_members(void *obj, void *arg, int flags)
+{
+	struct member *member = obj;
+	struct call_queue *q = arg;
+
+	if (!member->delme) {
+		if (member->dynamic) {
+			/* dynamic members were not counted toward the member count
+			 * when reloading members from queues.conf, so we do that here
+			 */
+			q->membercount++;
+		}
+		member->status = ast_device_state(member->state_interface);
+		return 0;
+	} else {
+		q->membercount--;
+		return CMP_MATCH;
+	}
+}
+
+/*! \brief Reload information pertaining to a particular queue
+ *
+ * Once we have isolated a queue within reload_queues, we call this. This will either
+ * reload information for the queue or if we're just reloading member information, we'll just
+ * reload that without touching other settings within the queue 
+ *
+ * \param cfg The configuration which we are reading
+ * \param mask Tells us what information we need to reload
+ * \param queuename The name of the queue we are reloading information from
+ * \retval void
+ */
+static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
+{
+	int new;
+	struct call_queue *q = NULL;
+	/*We're defining a queue*/
+	struct call_queue tmpq = {
+		.name = queuename,
+	};
+	const char *tmpvar;
+	const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
+	const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
+	int prev_weight = 0;
+	struct ast_variable *var;
+	if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
+		if (queue_reload) {
+			/* Make one then */
+			if (!(q = alloc_queue(queuename))) {
+				return;
+			}
+		} else {
+			/* Since we're not reloading queues, this means that we found a queue
+			 * in the configuration file which we don't know about yet. Just return.
+			 */
+			return;
+		}
+		new = 1;
+	} else {
+		new = 0;
+	}
+	
+	if (!new) {
+		ao2_lock(q);
+		prev_weight = q->weight ? 1 : 0;
+	}
+	/* Check if we already found a queue with this name in the config file */
+	if (q->found) {
+		ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
+		if (!new) {
+			/* It should be impossible to *not* hit this case*/
+			ao2_unlock(q);
+		}
+		queue_unref(q);
+		return;
+	}
+	/* Due to the fact that the "linear" strategy will have a different allocation
+	 * scheme for queue members, we must devise the queue's strategy before other initializations.
+	 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
+	 * container used will have only a single bucket instead of the typical number.
+	 */
+	if (queue_reload) {
+		if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
+			q->strategy = strat2int(tmpvar);
+			if (q->strategy < 0) {
+				ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
+				tmpvar, q->name);
+				q->strategy = QUEUE_STRATEGY_RINGALL;
+			}
+		} else {
+			q->strategy = QUEUE_STRATEGY_RINGALL;
+		}
+		init_queue(q);
+	}
+	if (member_reload) {
+		q->membercount = 0;
+		ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
+	}
+	for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
+		if (member_reload && !strcasecmp(var->name, "member")) {
+			reload_single_member(var->value, q);
+		} else if (queue_reload) {
+			queue_set_param(q, var->name, var->value, var->lineno, 1);
+		}
+	}
+	/* At this point, we've determined if the queue has a weight, so update use_weight
+	 * as appropriate
+	 */
+	if (!q->weight && prev_weight) {
+		ast_atomic_fetchadd_int(&use_weight, -1);
+	}
+	else if (q->weight && !prev_weight) {
+		ast_atomic_fetchadd_int(&use_weight, +1);
+	}
+
+	/* Free remaining members marked as delme */
+	if (member_reload) {
+		ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
+	}
+
+	if (new) {
+		ao2_link(queues, q);
+	} else {
+		ao2_unlock(q);
+	}
+	queue_unref(q);
+}
+
+static int mark_dead_and_unfound(void *obj, void *arg, int flags)
+{
+	struct call_queue *q = obj;
+	char *queuename = arg;
+	if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
+		q->dead = 1;
+		q->found = 0;
+	}
+	return 0;
+}
+
+static int kill_dead_queues(void *obj, void *arg, int flags)
+{
+	struct call_queue *q = obj;
+	char *queuename = arg;
+	if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
+		return CMP_MATCH;
+	} else {
+		return 0;
+	}
+}
+
+/*! \brief reload the queues.conf file
+ *
+ * This function reloads the information in the general section of the queues.conf
+ * file and potentially more, depending on the value of mask.
+ *
+ * \param reload 0 if we are calling this the first time, 1 every other time
+ * \param mask Gives flags telling us what information to actually reload
+ * \param queuename If set to a non-zero string, then only reload information from
+ * that particular queue. Otherwise inspect all queues
+ * \retval -1 Failure occurred 
+ * \retval 0 All clear!
+ */
+static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
+{
+	struct ast_config *cfg;
+	char *cat;
+	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+	const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
+
 	if (!(cfg = ast_config_load("queues.conf", config_flags))) {
 		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
-		return 0;
+		return -1;
 	} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
 		return 0;
 	} else if (cfg == CONFIG_STATUS_FILEINVALID) {
 		ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
-		return 0;
+		return -1;
 	}
+
+	/* We've made it here, so it looks like we're doing operations on all queues. */
 	ao2_lock(queues);
-	use_weight=0;
-	/* Mark all queues as dead for the moment */
-	queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
-	while ((q = ao2_iterator_next(&queue_iter))) {
-		if (!q->realtime) {
-			q->dead = 1;
-			q->found = 0;
-		}
-		queue_unref(q);
+	
+	/* Mark all queues as dead for the moment if we're reloading queues.
+	 * For clarity, we could just be reloading members, in which case we don't want to mess
+	 * with the other queue parameters at all*/
+	if (queue_reload) {
+		ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
 	}
 
 	/* Chug through config file */
 	cat = NULL;
 	while ((cat = ast_category_browse(cfg, cat)) ) {
-		if (!strcasecmp(cat, "general")) {	
-			/* Initialize global settings */
-			queue_keep_stats = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "keepstats")))
-				queue_keep_stats = ast_true(general_val);
-			queue_persistent_members = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
-				queue_persistent_members = ast_true(general_val);
-			autofill_default = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
-				autofill_default = ast_true(general_val);
-			montype_default = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
-				if (!strcasecmp(general_val, "mixmonitor"))
-					montype_default = 1;
-			}
-			update_cdr = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
-				update_cdr = ast_true(general_val);
-			shared_lastcall = 0;
-			if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
-				shared_lastcall = ast_true(general_val);
-		} else {	/* Define queue */
-			/* Look for an existing one */
-			struct call_queue tmpq = {
-				.name = cat,
-			};
-			if (!(q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
-				/* Make one then */
-				if (!(q = alloc_queue(cat))) {
-					/* TODO: Handle memory allocation failure */
-				}
-				new = 1;
-			} else
-				new = 0;
-			if (q) {
-				const char *tmpvar = NULL;
-				if (!new)
-					ao2_lock(q);
-				/* Check if a queue with this name already exists */
-				if (q->found) {
-					ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
-					if (!new) {
-						ao2_unlock(q);
-						queue_unref(q);
-					}
-					continue;
-				}
-				/* Due to the fact that the "linear" strategy will have a different allocation
-				 * scheme for queue members, we must devise the queue's strategy before other initializations
-				 */
-				if ((tmpvar = ast_variable_retrieve(cfg, cat, "strategy"))) {
-					q->strategy = strat2int(tmpvar);
-					if (q->strategy < 0) {
-						ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
-						tmpvar, q->name);
-						q->strategy = QUEUE_STRATEGY_RINGALL;
-					}
-				} else
-					q->strategy = QUEUE_STRATEGY_RINGALL;
-				/* Re-initialize the queue, and clear statistics */
-				init_queue(q);
-				if (!queue_keep_stats) 
-					clear_queue(q);
-				mem_iter = ao2_iterator_init(q->members, 0);
-				while ((cur = ao2_iterator_next(&mem_iter))) {
-					if (!cur->dynamic) {
-						cur->delme = 1;
-					}
-					ao2_ref(cur, -1);
-				}
-				for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
-					if (!strcasecmp(var->name, "member")) {
-						struct member tmpmem;
-						membername = NULL;
-
-						/* Add a new member */
-						ast_copy_string(parse, var->value, sizeof(parse));
-						
-						AST_STANDARD_APP_ARGS(args, parse);
-
-						interface = args.interface;
-						if (!ast_strlen_zero(args.penalty)) {
-							tmp = args.penalty;
-							while (*tmp && *tmp < 33) tmp++;
-							penalty = atoi(tmp);
-							if (penalty < 0) {
-								penalty = 0;
-							}
-						} else
-							penalty = 0;
-
-						if (!ast_strlen_zero(args.membername)) {
-							membername = args.membername;
-							while (*membername && *membername < 33) membername++;
-						}
-
-						if (!ast_strlen_zero(args.state_interface)) {
-							state_interface = args.state_interface;
-							while (*state_interface && *state_interface < 33) state_interface++;
-						} else
-							state_interface = interface;
-
-						/* Find the old position in the list */
-						ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
-						cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
-						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);
-						ao2_link(q->members, newm);
-						ao2_ref(newm, -1);
-						newm = NULL;
-
-						if (cur)
-							ao2_ref(cur, -1);
-						else {
-							q->membercount++;
-						}
-					} else {
-						queue_set_param(q, var->name, var->value, var->lineno, 1);
-					}
-				}
-
-				/* Free remaining members marked as delme */
-				mem_iter = ao2_iterator_init(q->members, 0);
-				while ((cur = ao2_iterator_next(&mem_iter))) {
-					if (! cur->delme) {
-						ao2_ref(cur, -1);
-						continue;
-					}
-					q->membercount--;
-					ao2_unlink(q->members, cur);
-					ao2_ref(cur, -1);
-				}
-
-				if (new) {
-					ao2_link(queues, q);
-				} else 
-					ao2_unlock(q);
-				queue_unref(q);
-			}
+		if (!strcasecmp(cat, "general") && queue_reload) {
+			queue_set_global_params(cfg);
+			continue;
 		}
+		if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
+			reload_single_queue(cfg, mask, cat);
 	}
+
 	ast_config_destroy(cfg);
-	queue_iter = ao2_iterator_init(queues, 0);
-	while ((q = ao2_iterator_next(&queue_iter))) {
-		if (q->dead) {
-			ao2_unlink(queues, q);
-		} else {
-			ao2_lock(q);
-			mem_iter = ao2_iterator_init(q->members, 0);
-			while ((cur = ao2_iterator_next(&mem_iter))) {
-				if (cur->dynamic)
-					q->membercount++;
-				cur->status = ast_device_state(cur->state_interface);
-				ao2_ref(cur, -1);
-			}
-			ao2_unlock(q);
-		}
-		queue_unref(q);
+	/* Unref all the dead queues if we were reloading queues */
+	if (queue_reload) {
+		ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
 	}
 	ao2_unlock(queues);
-	return 1;
+	return 0;
+}
+  
+/*! \brief Facilitates resetting statistics for a queue
+ *
+ * This function actually does not reset any statistics, but
+ * rather finds a call_queue struct which corresponds to the
+ * passed-in queue name and passes that structure to the 
+ * clear_queue function. If no queuename is passed in, then
+ * all queues will have their statistics reset.
+ *
+ * \param queuename The name of the queue to reset the statistics
+ * for. If this is NULL or zero-length, then this means to reset
+ * the statistics for all queues
+ * \retval void
+ */
+static int clear_stats(const char *queuename)
+{
+	struct call_queue *q;
+	struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
+	while ((q = ao2_iterator_next(&queue_iter))) {
+		ao2_lock(q);
+		if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
+			clear_queue(q);
+		ao2_unlock(q);
+	}
+	return 0;
+}
+
+/*! \brief The command center for all reload operations
+ *
+ * Whenever any piece of queue information is to be reloaded, this function
+ * is called. It interprets the flags set in the mask parameter and acts
+ * based on how they are set.
+ *
+ * \param reload True if we are reloading information, false if we are loading
+ * information for the first time.
+ * \param mask A bitmask which tells the handler what actions to take
+ * \param queuename The name of the queue on which we wish to take action
+ * \retval 0 All reloads were successful
+ * \retval non-zero There was a failure
+ */
+static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
+{
+	int res = 0;
+
+	if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
+		res |= reload_queue_rules(reload);
+	}
+	if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
+		res |= clear_stats(queuename);
+	}
+	if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
+		res |= reload_queues(reload, mask, queuename);
+	}
+	return res;
 }
 
 /*! \brief direct ouput to manager or cli with proper terminator */
@@ -6256,6 +6425,53 @@ static int manager_queue_log_custom(struct mansession *s, const struct message *
 	return 0;
 }
 
+static int manager_queue_reload(struct mansession *s, const struct message *m)
+{
+	struct ast_flags mask = {0,};
+	const char *queuename = NULL;
+	int header_found = 0;
+
+	queuename = astman_get_header(m, "Queue");
+	if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
+		header_found = 1;
+	}
+	if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_RULES);
+		header_found = 1;
+	}
+	if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
+		header_found = 1;
+	}
+
+	if (!header_found) {
+		ast_set_flag(&mask, AST_FLAGS_ALL);
+	}
+
+	if (!reload_handler(1, &mask, queuename)) {
+		astman_send_ack(s, m, "Queue reloaded successfully");
+	} else {
+		astman_send_error(s, m, "Error encountered while reloading queue");
+	}
+	return 0;
+}
+
+static int manager_queue_reset(struct mansession *s, const struct message *m)
+{
+	const char *queuename = NULL;
+	struct ast_flags mask = {QUEUE_RESET_STATS,};
+	
+	queuename = astman_get_header(m, "Queue");
+
+	if (!reload_handler(1, &mask, queuename)) {
+		astman_send_ack(s, m, "Queue stats reset successfully");
+	} else {
+		astman_send_error(s, m, "Error encountered while resetting queue stats");
+	}
+	return 0;
+}
+
 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
 {
 	/* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
@@ -6662,19 +6878,100 @@ static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast
 	return CLI_SUCCESS; 
 }
 
-static char *handle_queue_rule_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
+	struct ast_flags mask = {QUEUE_RESET_STATS,};
+	int i;
+
 	switch (cmd) {
 		case CLI_INIT:
-			e->command = "queue reload rules";
-			e->usage = 
-				"Usage: queue reload rules\n"
-				"	Reloads rules defined in queuerules.conf\n";
+			e->command = "queue reset stats";
+			e->usage =
+				"Usage: queue reset stats [<queuenames>]\n"
+				"\n"
+				"Issuing this command will reset statistics for\n"
+				"<queuenames>, or for all queues if no queue is\n"
+				"specified.\n";
 			return NULL;
 		case CLI_GENERATE:
+			if (a->pos >= 3) {
+				return complete_queue(a->line, a->word, a->pos, a->n);
+			} else {
+				return NULL;
+			}
+	}
+
+	if (a->argc < 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (a->argc == 3) {
+		reload_handler(1, &mask, NULL);
+		return CLI_SUCCESS;
+	}
+
+	for (i = 3; i < a->argc; ++i) {
+		reload_handler(1, &mask, a->argv[i]);
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct ast_flags mask = {0,};
+	int i;
+
+	switch (cmd) {
+		case CLI_INIT:
+			e->command = "queue reload {parameters|members|rules|all}";
+			e->usage =
+				"Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
+				"Reload queues. If <queuenames> are specified, only reload information pertaining\n"
+				"to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
+				"specified in order to know what information to reload. Below is an explanation\n"
+				"of each of these qualifiers.\n"
+				"\n"
+				"\t'members' - reload queue members from queues.conf\n"
+				"\t'parameters' - reload all queue options except for queue members\n"
+				"\t'rules' - reload the queuerules.conf file\n"
+				"\t'all' - reload queue rules, parameters, and members\n"
+				"\n"
+				"Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
+				"Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
+				"one queue is specified when using this command, reloading queue rules may cause\n"
+				"other queues to be affected\n";
 			return NULL;
+		case CLI_GENERATE:
+			if (a->pos >= 3) {
+				return complete_queue(a->line, a->word, a->pos, a->n);
+			} else {
+				return NULL;
+			}
 	}
-	reload_queue_rules(1);
+
+	if (a->argc < 3)
+		return CLI_SHOWUSAGE;
+
+	if (!strcasecmp(a->argv[2], "rules")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_RULES);
+	} else if (!strcasecmp(a->argv[2], "members")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
+	} else if (!strcasecmp(a->argv[2], "parameters")) {
+		ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
+	} else if (!strcasecmp(a->argv[2], "all")) {
+		ast_set_flag(&mask, AST_FLAGS_ALL);
+	}
+
+	if (a->argc == 3) {
+		reload_handler(1, &mask, NULL);
+		return CLI_SUCCESS;
+	}
+
+	for (i = 3; i < a->argc; ++i) {
+		reload_handler(1, &mask, a->argv[i]);
+	}
+
 	return CLI_SUCCESS;
 }
 
@@ -6694,7 +6991,8 @@ static struct ast_cli_entry cli_queue[] = {
 	AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
 	AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
 	AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
-	AST_CLI_DEFINE(handle_queue_rule_reload, "Reload the rules defined in queuerules.conf"),
+	AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
+	AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
 };
 
 static int unload_module(void)
@@ -6750,10 +7048,13 @@ static int load_module(void)
 {
 	int res;
 	struct ast_context *con;
+	struct ast_flags mask = {AST_FLAGS_ALL, };
 
 	queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
 
-	if (!reload_queues(0))
+	use_weight = 0;
+
+	if (reload_handler(0, &mask, NULL))
 		return AST_MODULE_LOAD_DECLINE;
 
 	con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
@@ -6781,6 +7082,8 @@ static int load_module(void)
 	res |= ast_manager_register("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom, "Adds custom entry in queue_log");
 	res |= ast_manager_register("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty, "Set the penalty for a queue member"); 
 	res |= ast_manager_register("QueueRule", 0, manager_queue_rule_show, "Queue Rules");
+	res |= ast_manager_register("QueueReload", 0, manager_queue_reload, "Reload a queue, queues, or any sub-section of a queue or queues");
+	res |= ast_manager_register("QueueReset", 0, manager_queue_reset, "Reset queue statistics");
 	res |= ast_custom_function_register(&queuevar_function);
 	res |= ast_custom_function_register(&queuemembercount_function);
 	res |= ast_custom_function_register(&queuemembercount_dep);
@@ -6803,8 +7106,9 @@ static int load_module(void)
 
 static int reload(void)
 {
+	struct ast_flags mask = {AST_FLAGS_ALL,};
 	ast_unload_realtime("queue_members");
-	reload_queues(1);
+	reload_handler(1, &mask, NULL);
 	return 0;
 }
 
diff --git a/doc/manager_1_1.txt b/doc/manager_1_1.txt
index 2089e0253c658b7acd8e7802f8c035149d69ef38..03d10a4700acb61563337b66ab32937802a6f1ca 100644
--- a/doc/manager_1_1.txt
+++ b/doc/manager_1_1.txt
@@ -202,6 +202,23 @@ Changes to manager version 1.1:
 	Variables:
 	  ActionId: <id>		Action ID for this transaction. Will be returned.
 
+- Action: QueueReload
+	Modules: app_queue
+	Purpose:
+		To reload queue rules, a queue's members, a queue's parameters, or all of the aforementioned
+	Variable:
+		Queuename: <name> The name of the queue to take action on. If no queue name is specified, then all queues are affected
+		Rules: <yes or no> Whether to reload queue_rules.conf
+		Members: <yes or no> Whether to reload the queue's members
+		Parameters: <yes or no> Whether to reload the other queue options
+
+- Action: QueueReset
+	Modules: app_queue
+	Purpose:
+		Reset the statistics for a queue
+	Variables:
+		Queuename: <name> The name of the queue on which to reset statistics
+
 * NEW EVENTS
 ------------