diff --git a/install/data/defaults.json b/install/data/defaults.json
index d883742495..ed0ed1e2bf 100644
--- a/install/data/defaults.json
+++ b/install/data/defaults.json
@@ -13,7 +13,6 @@
     "maximumTagLength": 15,
     "allowTopicsThumbnail": 0,
     "registrationType": "normal",
-    "allowLocalLogin": 1,
     "allowAccountDelete": 1,
     "allowFileUploads": 0,
     "allowedFileExtensions": "png,jpg,bmp",
diff --git a/public/language/en-GB/admin/manage/privileges.json b/public/language/en-GB/admin/manage/privileges.json
index eddca6d5b6..07d0a4de50 100644
--- a/public/language/en-GB/admin/manage/privileges.json
+++ b/public/language/en-GB/admin/manage/privileges.json
@@ -10,6 +10,7 @@
 	"search-content": "Search Content",
 	"search-users": "Search Users",
 	"search-tags": "Search Tags",
+	"allow-local-login": "Local Login",
 
 	"find-category": "Find Category",
 	"access-category": "Access Category",
diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json
index 664bff67f7..99b6e05a58 100644
--- a/public/language/en-GB/admin/settings/user.json
+++ b/public/language/en-GB/admin/settings/user.json
@@ -1,6 +1,5 @@
 {
 	"authentication": "Authentication",
-	"allow-local-login": "Allow local login",
 	"require-email-confirmation": "Require Email Confirmation",
 	"email-confirm-interval": "User may not resend a confirmation email until",
 	"email-confirm-email2": "minutes have elapsed",
diff --git a/src/cli/reset.js b/src/cli/reset.js
index 44d78df961..d3675d2ee4 100644
--- a/src/cli/reset.js
+++ b/src/cli/reset.js
@@ -11,6 +11,7 @@ var events = require('../events');
 var meta = require('../meta');
 var plugins = require('../plugins');
 var widgets = require('../widgets');
+var privileges = require('../privileges');
 
 var dirname = require('./paths').baseDir;
 
@@ -86,9 +87,13 @@ exports.reset = function (options, callback) {
 };
 
 function resetSettings(callback) {
-	meta.configs.set('allowLocalLogin', 1, function (err) {
+	privileges.global.give(['local:login'], 'registered-users', function (err) {
+		if (err) {
+			return callback(err);
+		}
+		winston.info('[reset] registered-users given login privilege');
 		winston.info('[reset] Settings reset to default');
-		callback(err);
+		callback();
 	});
 }
 
diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js
index 5dd4d62efe..941ec5bcc9 100644
--- a/src/controllers/authentication.js
+++ b/src/controllers/authentication.js
@@ -14,7 +14,7 @@ var plugins = require('../plugins');
 var utils = require('../utils');
 var translator = require('../translator');
 var helpers = require('./helpers');
-
+var privileges = require('../privileges');
 var sockets = require('../socket.io');
 
 var authenticationController = module.exports;
@@ -404,6 +404,9 @@ authenticationController.localLogin = function (req, username, password, next) {
 				banned: function (next) {
 					user.isBanned(uid, next);
 				},
+				hasLoginPrivilege: function (next) {
+					privileges.global.can('local:login', uid, next);
+				},
 			}, next);
 		},
 		function (result, next) {
@@ -412,7 +415,7 @@ authenticationController.localLogin = function (req, username, password, next) {
 				isAdminOrGlobalMod: result.isAdminOrGlobalMod,
 			});
 
-			if (!result.isAdminOrGlobalMod && parseInt(meta.config.allowLocalLogin, 10) === 0) {
+			if (parseInt(uid, 10) && !result.hasLoginPrivilege) {
 				return next(new Error('[[error:local-login-disabled]]'));
 			}
 
diff --git a/src/controllers/index.js b/src/controllers/index.js
index a91636dfc7..a183692d4e 100644
--- a/src/controllers/index.js
+++ b/src/controllers/index.js
@@ -7,6 +7,7 @@ var validator = require('validator');
 var meta = require('../meta');
 var user = require('../user');
 var plugins = require('../plugins');
+var privileges = require('../privileges');
 var helpers = require('./helpers');
 
 var Controllers = module.exports;
@@ -106,7 +107,6 @@ Controllers.login = function (req, res, next) {
 
 	data.alternate_logins = loginStrategies.length > 0;
 	data.authentication = loginStrategies;
-	data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1 || parseInt(req.query.local, 10) === 1;
 	data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval' || registrationType === 'admin-approval-ip';
 	data.allowLoginWith = '[[login:' + allowLoginWith + ']]';
 	data.breadcrumbs = helpers.buildBreadcrumbs([{
@@ -115,26 +115,33 @@ Controllers.login = function (req, res, next) {
 	data.error = req.flash('error')[0] || errorText;
 	data.title = '[[pages:login]]';
 
-	if (!data.allowLocalLogin && !data.allowRegistration && data.alternate_logins && data.authentication.length === 1) {
-		if (res.locals.isAPI) {
-			return helpers.redirect(res, {
-				external: nconf.get('relative_path') + data.authentication[0].url,
-			});
+	privileges.global.canGroup('local:login', 'registered-users', function (err, hasLoginPrivilege) {
+		if (err) {
+			return next(err);
 		}
-		return res.redirect(nconf.get('relative_path') + data.authentication[0].url);
-	}
-	if (req.loggedIn) {
-		user.getUserFields(req.uid, ['username', 'email'], function (err, user) {
-			if (err) {
-				return next(err);
+
+		data.allowLocalLogin = hasLoginPrivilege || parseInt(req.query.local, 10) === 1;
+		if (!data.allowLocalLogin && !data.allowRegistration && data.alternate_logins && data.authentication.length === 1) {
+			if (res.locals.isAPI) {
+				return helpers.redirect(res, {
+					external: nconf.get('relative_path') + data.authentication[0].url,
+				});
 			}
-			data.username = allowLoginWith === 'email' ? user.email : user.username;
-			data.alternate_logins = false;
+			return res.redirect(nconf.get('relative_path') + data.authentication[0].url);
+		}
+		if (req.loggedIn) {
+			user.getUserFields(req.uid, ['username', 'email'], function (err, user) {
+				if (err) {
+					return next(err);
+				}
+				data.username = allowLoginWith === 'email' ? user.email : user.username;
+				data.alternate_logins = false;
+				res.render('login', data);
+			});
+		} else {
 			res.render('login', data);
-		});
-	} else {
-		res.render('login', data);
-	}
+		}
+	});
 };
 
 Controllers.register = function (req, res, next) {
diff --git a/src/install.js b/src/install.js
index cd628b13d9..5ef191cf44 100644
--- a/src/install.js
+++ b/src/install.js
@@ -381,7 +381,10 @@ function createGlobalModeratorsGroup(next) {
 
 function giveGlobalPrivileges(next) {
 	var privileges = require('./privileges');
-	var defaultPrivileges = ['chat', 'upload:post:image', 'signature', 'search:content', 'search:users', 'search:tags'];
+	var defaultPrivileges = [
+		'chat', 'upload:post:image', 'signature', 'search:content',
+		'search:users', 'search:tags', 'local:login',
+	];
 	privileges.global.give(defaultPrivileges, 'registered-users', next);
 }
 
diff --git a/src/privileges/global.js b/src/privileges/global.js
index 554adf0bed..5d0cb88213 100644
--- a/src/privileges/global.js
+++ b/src/privileges/global.js
@@ -21,6 +21,7 @@ module.exports = function (privileges) {
 		{ name: '[[admin/manage/privileges:search-content]]' },
 		{ name: '[[admin/manage/privileges:search-users]]' },
 		{ name: '[[admin/manage/privileges:search-tags]]' },
+		{ name: '[[admin/manage/privileges:allow-local-login]]' },
 	];
 
 	privileges.global.userPrivilegeList = [
@@ -32,6 +33,7 @@ module.exports = function (privileges) {
 		'search:content',
 		'search:users',
 		'search:tags',
+		'local:login',
 	];
 
 	privileges.global.groupPrivilegeList = privileges.global.userPrivilegeList.map(function (privilege) {
@@ -111,6 +113,10 @@ module.exports = function (privileges) {
 		], callback);
 	};
 
+	privileges.global.canGroup = function (privilege, groupName, callback) {
+		groups.isMember(groupName, 'cid:0:privileges:groups:' + privilege, callback);
+	};
+
 	privileges.global.give = function (privileges, groupName, callback) {
 		helpers.giveOrRescind(groups.join, privileges, 0, groupName, callback);
 	};
diff --git a/src/upgrades/1.10.2/local_login_privileges.js b/src/upgrades/1.10.2/local_login_privileges.js
new file mode 100644
index 0000000000..005d74afac
--- /dev/null
+++ b/src/upgrades/1.10.2/local_login_privileges.js
@@ -0,0 +1,17 @@
+'use strict';
+
+module.exports = {
+	name: 'Give global local login privileges',
+	timestamp: Date.UTC(2018, 8, 28),
+	method: function (callback) {
+		var meta = require('../../meta');
+		var privileges = require('../../privileges');
+		var allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1;
+
+		if (allowLocalLogin) {
+			privileges.global.give(['local:login'], 'registered-users', callback);
+		} else {
+			callback();
+		}
+	},
+};
diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl
index 5b1a003068..415c516477 100644
--- a/src/views/admin/settings/user.tpl
+++ b/src/views/admin/settings/user.tpl
@@ -4,13 +4,6 @@
 	<div class="col-sm-2 col-xs-12 settings-header">[[admin/settings/user:authentication]]</div>
 	<div class="col-sm-10 col-xs-12">
 		<form role="form">
-			<div class="checkbox">
-				<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
-					<input class="mdl-switch__input" type="checkbox" data-field="allowLocalLogin" checked>
-					<span class="mdl-switch__label"><strong>[[admin/settings/user:allow-local-login]]</strong></span>
-				</label>
-			</div>
-
 			<div class="checkbox">
 				<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
 					<input class="mdl-switch__input" type="checkbox" data-field="requireEmailConfirmation">
diff --git a/test/authentication.js b/test/authentication.js
index 2c03d9549d..f22ae7fc04 100644
--- a/test/authentication.js
+++ b/test/authentication.js
@@ -9,6 +9,7 @@ var async = require('async');
 var db = require('./mocks/databasemock');
 var user = require('../src/user');
 var meta = require('../src/meta');
+var privileges = require('../src/privileges');
 var helpers = require('./helpers');
 
 describe('authentication', function () {
@@ -328,15 +329,15 @@ describe('authentication', function () {
 		});
 	});
 
-
 	it('should fail to login if local login is disabled', function (done) {
-		meta.config.allowLocalLogin = 0;
-		loginUser('someuser', 'somepass', function (err, response, body) {
-			meta.config.allowLocalLogin = 1;
+		privileges.global.rescind(['local:login'], 'registered-users', function (err) {
 			assert.ifError(err);
-			assert.equal(response.statusCode, 403);
-			assert.equal(body, '[[error:local-login-disabled]]');
-			done();
+			loginUser('regular', 'regularpwd', function (err, response, body) {
+				assert.ifError(err);
+				assert.equal(response.statusCode, 403);
+				assert.equal(body, '[[error:local-login-disabled]]');
+				privileges.global.give(['local:login'], 'registered-users', done);
+			});
 		});
 	});
 
diff --git a/test/categories.js b/test/categories.js
index ce3f3f0b8d..53ece967ff 100644
--- a/test/categories.js
+++ b/test/categories.js
@@ -675,6 +675,7 @@ describe('Categories', function () {
 					'upload:post:image': false,
 					'upload:post:file': false,
 					signature: false,
+					'local:login': false,
 				});
 
 				done();
@@ -718,6 +719,7 @@ describe('Categories', function () {
 					'groups:upload:post:image': true,
 					'groups:upload:post:file': false,
 					'groups:signature': true,
+					'groups:local:login': true,
 				});
 
 				done();
diff --git a/test/controllers-admin.js b/test/controllers-admin.js
index b84d13c66c..d0bec4e74c 100644
--- a/test/controllers-admin.js
+++ b/test/controllers-admin.js
@@ -23,7 +23,6 @@ describe('Admin Controllers', function () {
 	var jar;
 
 	before(function (done) {
-		groups.resetCache();
 		async.series({
 			category: function (next) {
 				categories.create({
diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js
index 7fee6efede..53cf386eba 100644
--- a/test/mocks/databasemock.js
+++ b/test/mocks/databasemock.js
@@ -161,6 +161,11 @@ function setupMockDefaults(callback) {
 		function (next) {
 			db.emptydb(next);
 		},
+		function (next) {
+			var groups = require('../../src/groups');
+			groups.resetCache();
+			next();
+		},
 		function (next) {
 			winston.info('test_database flushed');
 			setupDefaultConfigs(meta, next);
@@ -213,7 +218,10 @@ function setupDefaultConfigs(meta, next) {
 
 function giveDefaultGlobalPrivileges(next) {
 	var privileges = require('../../src/privileges');
-	privileges.global.give(['chat', 'upload:post:image', 'signature', 'search:content', 'search:users', 'search:tags'], 'registered-users', next);
+	privileges.global.give([
+		'chat', 'upload:post:image', 'signature', 'search:content',
+		'search:users', 'search:tags', 'local:login',
+	], 'registered-users', next);
 }
 
 function enableDefaultPlugins(callback) {