diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c
index 1680196aa2322173bbd949ca66ec7d7bde84f5f2..f8ea864ff547c324b05764c35432997b92e5279f 100644
--- a/res/res_sorcery_config.c
+++ b/res/res_sorcery_config.c
@@ -39,9 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/astobj2.h"
 #include "asterisk/config.h"
 #include "asterisk/uuid.h"
-
-/*! \brief Default number of buckets for sorcery objects */
-#define DEFAULT_OBJECT_BUCKETS 53
+#include "asterisk/hashtab.h"
 
 /*! \brief Structure for storing configuration file sourced objects */
 struct sorcery_config {
@@ -183,7 +181,7 @@ static void *sorcery_config_retrieve_id(const struct ast_sorcery *sorcery, void
 	struct sorcery_config *config = data;
 	RAII_VAR(struct ao2_container *, objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
 
-	return objects ? ao2_find(objects, id, OBJ_KEY | OBJ_NOLOCK) : NULL;
+	return objects ? ao2_find(objects, id, OBJ_KEY) : NULL;
 }
 
 static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
@@ -237,6 +235,7 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
 	struct ast_category *category = NULL;
 	RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
 	const char *id = NULL;
+	unsigned int buckets = 0;
 
 	if (!cfg) {
 		ast_log(LOG_ERROR, "Unable to load config file '%s'\n", config->filename);
@@ -249,7 +248,37 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
 		return;
 	}
 
-	if (!(objects = ao2_container_alloc(config->buckets, sorcery_config_hash, sorcery_config_cmp))) {
+	if (!config->buckets) {
+		while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {
+
+			/* If given criteria has not been met skip the category, it is not applicable */
+			if (!sorcery_is_criteria_met(ast_category_first(category), config->criteria)) {
+				continue;
+			}
+
+			buckets++;
+		}
+
+		/* Determine the optimal number of buckets */
+		while (buckets && !ast_is_prime(buckets)) {
+			/* This purposely goes backwards to ensure that the container doesn't have a ton of
+			 * empty buckets for objects that will never get added.
+			 */
+			buckets--;
+		}
+
+		if (!buckets) {
+			buckets = 1;
+		}
+	} else {
+		buckets = config->buckets;
+	}
+
+	ast_debug(2, "Using bucket size of '%d' for objects of type '%s' from '%s'\n",
+		buckets, type, config->filename);
+
+	if (!(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, buckets,
+		sorcery_config_hash, sorcery_config_cmp))) {
 		ast_log(LOG_ERROR, "Could not create bucket for new objects from '%s', keeping existing objects\n",
 			config->filename);
 		ast_config_destroy(cfg);
@@ -288,7 +317,7 @@ static void sorcery_config_internal_load(void *data, const struct ast_sorcery *s
 			ast_log(LOG_NOTICE, "Retaining existing configuration for object of type '%s' with id '%s'\n", type, id);
 		}
 
-		ao2_link_flags(objects, obj, OBJ_NOLOCK);
+		ao2_link(objects, obj);
 	}
 
 	ao2_global_obj_replace_unref(config->objects, objects);
@@ -317,7 +346,6 @@ static void *sorcery_config_open(const char *data)
 	ast_uuid_generate_str(config->uuid, sizeof(config->uuid));
 
 	ast_rwlock_init(&config->objects.lock);
-	config->buckets = DEFAULT_OBJECT_BUCKETS;
 	strcpy(config->filename, filename);
 
 	while ((option = strsep(&tmp, ","))) {
@@ -325,8 +353,8 @@ static void *sorcery_config_open(const char *data)
 
 		if (!strcasecmp(name, "buckets")) {
 			if (sscanf(value, "%30u", &config->buckets) != 1) {
-				ast_log(LOG_ERROR, "Unsupported bucket size of '%s' used for configuration file '%s', defaulting to '%d'\n",
-					value, filename, DEFAULT_OBJECT_BUCKETS);
+				ast_log(LOG_ERROR, "Unsupported bucket size of '%s' used for configuration file '%s', defaulting to automatic determination\n",
+					value, filename);
 			}
 		} else if (!strcasecmp(name, "integrity")) {
 			if (!strcasecmp(value, "file")) {