diff --git a/UPGRADE.txt b/UPGRADE.txt
index 82eeff453a4d12b61c4b0df525e39dccef3bb7ec..209ebd50d86776e520688d50a98ae8415f1d6431 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -291,6 +291,13 @@ Queues:
   new value has been added to the TRANSFER event that indicates the caller's
   original position in the queue they are being transfered from.
 
+* Prior to Asterisk 1.6.2, queue names were treated in a case-sensitive
+  manner, meaning that queues with names like "sales" and "sALeS" would
+  be seen as unique queues. The parsing logic has changed to use case-
+  insensitive comparisons now when originally hashing based on queue
+  names, meaning that now the two queues mentioned as examples earlier
+  will be seen as having the same name.
+
 iLBC Codec:
 
 * Previously, the Asterisk source code distribution included the iLBC
diff --git a/apps/app_queue.c b/apps/app_queue.c
index b3081028d9cb1d68bd8c876726d1a8adb04a5119..07829042b62941497aeabb3f5278fc31cd53dcfe 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -67,6 +67,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <sys/time.h>
 #include <sys/signal.h>
 #include <netinet/in.h>
+#include <ctype.h>
 
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
@@ -850,7 +851,8 @@ static int strat2int(const char *strategy)
 static int queue_hash_cb(const void *obj, const int flags)
 {
 	const struct call_queue *q = obj;
-	return ast_str_hash(q->name);
+
+	return ast_str_case_hash(q->name);
 }
 
 static int queue_cmp_cb(void *obj, void *arg, void *data, int flags)
@@ -1671,7 +1673,6 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
 			/* Delete if unused (else will be deleted when last caller leaves). */
 			ao2_unlink(queues, q);
 			ao2_unlock(q);
-			queue_unref(q);
 		}
 		return NULL;
 	}
@@ -2192,8 +2193,6 @@ static void leave_queue(struct queue_ent *qe)
 	if (q->dead) {	
 		/* It's dead and nobody is in it, so kill it */
 		ao2_unlink(queues, q);
-		/* unref the container's reference to the queue */
-		queue_unref(q);
 	}
 	/* unref the explicit ref earlier in the function */
 	queue_unref(q);
@@ -2248,11 +2247,10 @@ static int compare_weight(struct call_queue *rq, struct member *member)
 			}
 		}
 		ao2_unlock(q);
+		queue_unref(q);
 		if (found) {
-			queue_unref(q);
 			break;
 		}
-		queue_unref(q);
 	}
 	return found;
 }
@@ -4186,6 +4184,8 @@ static int remove_from_queue(const char *queuename, const char *interface)
 			if (!mem->dynamic) {
 				ao2_ref(mem, -1);
 				ao2_unlock(q);
+				queue_unref(q);
+				ao2_unlock(queues);
 				return RES_NOT_DYNAMIC;
 			}
 			q->membercount--;
@@ -5691,13 +5691,15 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 		}
 	}
 
-	queue_iter = ao2_iterator_init(queues, 0);
+	queue_iter = ao2_iterator_init(queues, F_AO2I_DONTLOCK);
+	ao2_lock(queues);
 	while ((q = ao2_iterator_next(&queue_iter))) {
 		float sl;
 
 		ao2_lock(q);
 		if (argc == 3 && strcasecmp(q->name, argv[2])) {
 			ao2_unlock(q);
+			queue_unref(q);
 			continue;
 		}
 		found = 1;
@@ -5768,6 +5770,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, char **argv)
 		}
 		queue_unref(q); /* Unref the iterator's reference */
 	}
+	ao2_unlock(queues);
 	if (!found) {
 		if (argc == 3)
 			ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h
index 5ad362e5697dbc8982e0ffe6541b88c438ad6529..142fc7c627aab4012d06ee7c9eff684bae480bca 100644
--- a/include/asterisk/strings.h
+++ b/include/asterisk/strings.h
@@ -23,6 +23,8 @@
 #ifndef _ASTERISK_STRINGS_H
 #define _ASTERISK_STRINGS_H
 
+#include <ctype.h>
+
 #include "asterisk/inline_api.h"
 #include "asterisk/utils.h"
 #include "asterisk/threadstorage.h"
@@ -738,4 +740,21 @@ static force_inline int ast_str_hash(const char *str)
 	return abs(hash);
 }
 
+/*!
+ * \brief Compute a hash value on a case-insensitive string
+ *
+ * Uses the same hash algorithm as ast_str_hash, but converts
+ * all characters to lowercase prior to computing a hash. This
+ * allows for easy case-insensitive lookups in a hash table.
+ */
+static force_inline int ast_str_case_hash(const char *str)
+{
+	int hash = 5381;
+
+	while (*str) {
+		hash = hash * 33 ^ tolower(*str++);
+	}
+
+	return abs(hash);
+}
 #endif /* _ASTERISK_STRINGS_H */