diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js
index 426dd902fd..a9985cabad 100644
--- a/public/src/forum/admin/categories.js
+++ b/public/src/forum/admin/categories.js
@@ -246,15 +246,15 @@ define(function() {
 			readMembers = modalEl.find('#category-permissions-read'),
 			writeMembers = modalEl.find('#category-permissions-write');
 		socket.emit('api:admin.categories.getPrivilegeSettings', cid, function(err, privilegeList) {
-			var	readLength = privilegeList['+r'].members.length,
-				writeLength = privilegeList['+w'].members.length,
+			var	readLength = privilegeList['+r'].length,
+				writeLength = privilegeList['+w'].length,
 				readFrag = document.createDocumentFragment(),
 				writeFrag = document.createDocumentFragment(),
 				liEl = document.createElement('li'),
 				x, userObj;
 
 			for(x=0;x<readLength;x++) {
-				userObj = privilegeList['+r'].members[x];
+				userObj = privilegeList['+r'][x];
 				liEl.setAttribute('data-uid', userObj.uid);
 
 				liEl.innerHTML = '<img src="' + userObj.picture + '" title="' + userObj.username + '" />';
@@ -262,7 +262,7 @@ define(function() {
 			}
 
 			for(x=0;x<writeLength;x++) {
-				userObj = privilegeList['+w'].members[x];
+				userObj = privilegeList['+w'][x];
 				liEl.setAttribute('data-uid', userObj.uid);
 
 				liEl.innerHTML = '<img src="' + userObj.picture + '" title="' + userObj.username + '" />';
diff --git a/src/categoryTools.js b/src/categoryTools.js
index 9fe38c80b2..ccbce0f4fd 100644
--- a/src/categoryTools.js
+++ b/src/categoryTools.js
@@ -8,20 +8,42 @@ var	Groups = require('./groups'),
 CategoryTools.privileges = function(cid, uid, callback) {
 	async.parallel({
 		"+r": function(next) {
-			Groups.exists('cid:' + cid + ':privileges:+r', function(err, exists) {
+			var	key = 'cid:' + cid + ':privileges:+r';
+			Groups.exists(key, function(err, exists) {
 				if (exists) {
-					Groups.isMemberByGroupName(uid, 'cid:' + cid + ':privileges:+r', next);
+					async.parallel({
+						isMember: function(next) {
+							Groups.isMemberByGroupName(uid, key, next);
+						},
+						isEmpty: function(next) {
+							Groups.isEmptyByGroupName(key, next);
+						}
+					}, next);
 				} else {
-					next(null, true);
+					next(null, {
+						isMember: false,
+						isEmpty: true
+					});
 				}
 			});
 		},
 		"+w": function(next) {
-			Groups.exists('cid:' + cid + ':privileges:+w', function(err, exists) {
+			var	key = 'cid:' + cid + ':privileges:+w';
+			Groups.exists(key, function(err, exists) {
 				if (exists) {
-					Groups.isMemberByGroupName(uid, 'cid:' + cid + ':privileges:+w', next);
+					async.parallel({
+						isMember: function(next) {
+							Groups.isMemberByGroupName(uid, key, next);
+						},
+						isEmpty: function(next) {
+							Groups.isEmptyByGroupName(key, next);
+						}
+					}, next);
 				} else {
-					next(null, true);
+					next(null, {
+						isMember: false,
+						isEmpty: true
+					});
 				}
 			});
 		},
@@ -33,10 +55,10 @@ CategoryTools.privileges = function(cid, uid, callback) {
 		}
 	}, function(err, privileges) {
 		callback(err, !privileges ? null : {
-			"+r": privileges['+r'],
-			"+w": privileges['+w'],
-			read: privileges['+r'] || privileges.moderator || privileges.admin,
-			write: privileges['+w'] || privileges.moderator || privileges.admin,
+			"+r": privileges['+r'].isMember,
+			"+w": privileges['+w'].isMember,
+			read: (privileges['+r'].isMember || privileges['+r'].isEmpty) || privileges.moderator || privileges.admin,
+			write: (privileges['+w'].isMember || privileges['+w'].isEmpty) || privileges.moderator || privileges.admin,
 			editable: privileges.moderator || privileges.admin,
 			view_deleted: privileges.moderator || privileges.admin
 		});
diff --git a/src/groups.js b/src/groups.js
index df6d6fa500..9dc6121107 100644
--- a/src/groups.js
+++ b/src/groups.js
@@ -105,6 +105,22 @@
 		});
 	};
 
+	Groups.isEmpty = function(gid, callback) {
+		RDB.scard('gid:' + gid + ':members', function(err, numMembers) {
+			callback(err, numMembers === 0);
+		});
+	};
+
+	Groups.isEmptyByGroupName = function(groupName, callback) {
+		Groups.getGidFromName(groupName, function(err, gid) {
+			if (err || !gid) {
+				callback(new Error('gid-not-found'));
+			} else {
+				Groups.isEmpty(gid, callback);
+			}
+		});
+	};
+
 	Groups.exists = function(name, callback) {
 		async.parallel({
 			exists: function(next) {
@@ -169,7 +185,9 @@
 	Groups.joinByGroupName = function(groupName, uid, callback) {
 		Groups.getGidFromName(groupName, function(err, gid) {
 			if (err || !gid) {
-				callback(new Error('gid-not-found'));
+				Groups.create(groupName, '', function(err, groupObj) {
+					Groups.join(groupObj.gid, uid, callback);
+				});
 			} else {
 				Groups.join(gid, uid, callback);
 			}
diff --git a/src/websockets.js b/src/websockets.js
index 7557e592c0..df0e007eeb 100644
--- a/src/websockets.js
+++ b/src/websockets.js
@@ -1016,7 +1016,19 @@ module.exports.init = function(io) {
 				"+w": function(next) {
 					Groups.getByGroupName('cid:' + cid + ':privileges:+w', { expand: true }, next);
 				}
-			}, callback);
+			}, function(err, data) {
+				if (!err) {
+					callback(null, {
+						"+r": data['+r'].members,
+						"+w": data['+w'].members
+					});
+				} else {
+					callback(null, {
+						"+r": [],
+						"+w": []
+					});
+				}
+			});
 		});
 
 		socket.on('api:admin.themes.getInstalled', function(callback) {