diff --git a/web/config.py b/web/config.py
index 2b314fe69..d02a91380 100644
--- a/web/config.py
+++ b/web/config.py
@@ -535,7 +535,7 @@ ENHANCED_COOKIE_PROTECTION = True
 ##########################################################################
 
 # Default setting is internal
-# External Supported Sources: ldap
+# External Supported Sources: ldap, kerberos
 # Multiple authentication can be achieved by setting this parameter to
 # ['ldap', 'internal']. pgAdmin will authenticate the user with ldap first,
 # in case of failure internal authentication will be done.
@@ -618,6 +618,26 @@ LDAP_CA_CERT_FILE = ''
 LDAP_CERT_FILE = ''
 LDAP_KEY_FILE = ''
 
+
+##########################################################################
+# Kerberos Configuration
+##########################################################################
+
+KRB_APP_HOST_NAME = DEFAULT_SERVER
+
+# If the default_keytab_name is not set in krb5.conf or
+# the KRB_KTNAME environment variable is not set then, explicitly set
+# the Keytab file
+
+KRB_KTNAME = '<KRB5_KEYTAB_FILE>'
+
+# After kerberos authentication, user will be added into the SQLite database
+# automatically, if set to True.
+# Set it to False, if user should not be added automatically,
+# in this case Admin has to add the user manually in the SQLite database.
+
+KRB_AUTO_CREATE_USER = True
+
 ##########################################################################
 # Local config settings
 ##########################################################################
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index ff9c00f50..14afe7dc1 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -35,6 +35,9 @@ else:
 import config
 from pgadmin import create_app
 from pgadmin.utils import u_encode, fs_encoding, file_quote
+from pgadmin.utils.constants import INTERNAL, LDAP,\
+    KERBEROS, SUPPORTED_AUTH_SOURCES
+
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
@@ -96,15 +99,11 @@ if config.SERVER_MODE:
     app.wsgi_app = ReverseProxied(app.wsgi_app)
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
-app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
+
 if len(config.AUTHENTICATION_SOURCES) > 0:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
 else:
-    app.PGADMIN_EXTERNAL_AUTH_SOURCE = app.PGADMIN_DEFAULT_AUTH_SOURCE
-
-app.logger.debug(
-    "Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
+    app.PGADMIN_EXTERNAL_AUTH_SOURCE = INTERNAL
 
 # Start the web server. The port number should have already been set by the
 # runtime if we're running in desktop mode, otherwise we'll just use the
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index dae0b8cd2..a73335371 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -43,6 +43,7 @@ from pgadmin.utils.ajax import internal_server_error, make_json_response
 from pgadmin.utils.csrf import pgCSRFProtect
 from pgadmin import authenticate
 from pgadmin.utils.security_headers import SecurityHeaders
+from pgadmin.utils.constants import KERBEROS
 
 # Explicitly set the mime-types so that a corrupted windows registry will not
 # affect pgAdmin 4 to be load properly. This will avoid the issues that may
@@ -674,6 +675,7 @@ def create_app(app_name=None):
 
         # Check the auth key is valid, if it's set, and we're not in server
         # mode, and it's not a help file request.
+
         if not config.SERVER_MODE and app.PGADMIN_INT_KEY != '' and ((
             'key' not in request.args or
             request.args['key'] != app.PGADMIN_INT_KEY) and
@@ -695,11 +697,19 @@ def create_app(app_name=None):
                 )
                 abort(401)
             login_user(user)
+        elif config.SERVER_MODE and\
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE ==\
+                KERBEROS and \
+                not current_user.is_authenticated and \
+                request.endpoint in ('redirects.index', 'security.login'):
+            return authenticate.login()
 
         # if the server is restarted the in memory key will be lost
         # but the user session may still be active. Logout the user
         # to get the key again when login
         if config.SERVER_MODE and current_user.is_authenticated and \
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE != \
+                KERBEROS and \
                 current_app.keyManager.get() is None and \
                 request.endpoint not in ('security.login', 'security.logout'):
             logout_user()
diff --git a/web/pgadmin/authenticate/__init__.py b/web/pgadmin/authenticate/__init__.py
index 7ede73cd8..1fdb66cf7 100644
--- a/web/pgadmin/authenticate/__init__.py
+++ b/web/pgadmin/authenticate/__init__.py
@@ -11,16 +11,21 @@
 
 import flask
 import pickle
-from flask import current_app, flash
+from flask import current_app, flash, Response, request, url_for,\
+    render_template
 from flask_babelex import gettext
 from flask_security import current_user
 from flask_security.views import _security, _ctx
 from flask_security.utils import config_value, get_post_logout_redirect, \
-    get_post_login_redirect
+    get_post_login_redirect, logout_user
+
 from flask import session
 
 import config
 from pgadmin.utils import PgAdminModule
+from pgadmin.utils.constants import KERBEROS
+from pgadmin.utils.csrf import pgCSRFProtect
+
 from .registry import AuthSourceRegistry
 
 MODULE_NAME = 'authenticate'
@@ -28,12 +33,34 @@ MODULE_NAME = 'authenticate'
 
 class AuthenticateModule(PgAdminModule):
     def get_exposed_url_endpoints(self):
-        return ['authenticate.login']
+        return ['authenticate.login',
+                'authenticate.kerberos_login',
+                'authenticate.kerberos_logout']
 
 
 blueprint = AuthenticateModule(MODULE_NAME, __name__, static_url_path='')
 
 
+@blueprint.route("/login/kerberos",
+                 endpoint="kerberos_login", methods=["GET"])
+@pgCSRFProtect.exempt
+def kerberos_login():
+    logout_user()
+    return Response(render_template("browser/kerberos_login.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
+@blueprint.route("/logout/kerberos",
+                 endpoint="kerberos_logout", methods=["GET"])
+@pgCSRFProtect.exempt
+def kerberos_logout():
+    logout_user()
+    return Response(render_template("browser/kerberos_logout.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
 @blueprint.route('/login', endpoint='login', methods=['GET', 'POST'])
 def login():
     """
@@ -56,15 +83,24 @@ def login():
     if status:
         # Login the user
         status, msg = auth_obj.login()
+        current_auth_obj = auth_obj.as_dict()
         if not status:
+            if current_auth_obj['current_source'] ==\
+                    KERBEROS:
+                return flask.redirect('{0}?next={1}'.format(url_for(
+                    'authenticate.kerberos_login'), url_for('browser.index')))
+
             flash(gettext(msg), 'danger')
             return flask.redirect(get_post_logout_redirect())
 
-        session['_auth_source_manager_obj'] = auth_obj.as_dict()
+        session['_auth_source_manager_obj'] = current_auth_obj
         return flask.redirect(get_post_login_redirect())
 
+    elif isinstance(msg, Response):
+        return msg
     flash(gettext(msg), 'danger')
-    return flask.redirect(get_post_logout_redirect())
+    response = flask.redirect(get_post_logout_redirect())
+    return response
 
 
 class AuthSourceManager():
@@ -75,6 +111,7 @@ class AuthSourceManager():
         self.auth_sources = sources
         self.source = None
         self.source_friendly_name = None
+        self.current_source = None
 
     def as_dict(self):
         """
@@ -84,9 +121,17 @@ class AuthSourceManager():
         res = dict()
         res['source_friendly_name'] = self.source_friendly_name
         res['auth_sources'] = self.auth_sources
+        res['current_source'] = self.current_source
 
         return res
 
+    def set_current_source(self, source):
+        self.current_source = source
+
+    @property
+    def get_current_source(self, source):
+        return self.current_source
+
     def set_source(self, source):
         self.source = source
 
@@ -115,9 +160,33 @@ class AuthSourceManager():
         msg = None
         for src in self.auth_sources:
             source = get_auth_sources(src)
+            current_app.logger.debug(
+                "Authentication initiated via source: %s" %
+                source.get_source_name())
+
+            if self.form.data['email'] and self.form.data['password'] and \
+                    source.get_source_name() == KERBEROS:
+                continue
+
             status, msg = source.authenticate(self.form)
+
+            # When server sends Unauthorized header to get the ticket over HTTP
+            # OR When kerberos authentication failed while accessing pgadmin,
+            # we need to break the loop as no need to authenticate further
+            # even if the authentication sources set to multiple
+            if not status:
+                if (hasattr(msg, 'status') and
+                    msg.status == '401 UNAUTHORIZED') or\
+                        (source.get_source_name() ==
+                         KERBEROS and
+                         request.method == 'GET'):
+                    break
+
             if status:
                 self.set_source(source)
+                self.set_current_source(source.get_source_name())
+                if msg is not None and 'username' in msg:
+                    self.form._fields['email'].data = msg['username']
                 return status, msg
         return status, msg
 
@@ -125,6 +194,9 @@ class AuthSourceManager():
         status, msg = self.source.login(self.form)
         if status:
             self.set_source_friendly_name(self.source.get_friendly_name())
+            current_app.logger.debug(
+                "Authentication and Login successfully done via source : %s" %
+                self.source.get_source_name())
         return status, msg
 
 
diff --git a/web/pgadmin/authenticate/internal.py b/web/pgadmin/authenticate/internal.py
index 804a487c7..484a7fdca 100644
--- a/web/pgadmin/authenticate/internal.py
+++ b/web/pgadmin/authenticate/internal.py
@@ -18,6 +18,7 @@ from flask_babelex import gettext
 from .registry import AuthSourceRegistry
 from pgadmin.model import User
 from pgadmin.utils.validation_utils import validate_email
+from pgadmin.utils.constants import INTERNAL
 
 
 @six.add_metaclass(AuthSourceRegistry)
@@ -31,7 +32,11 @@ class BaseAuthentication(object):
         'INVALID_EMAIL': gettext('Email/Username is not valid')
     }
 
-    @abstractproperty
+    @abstractmethod
+    def get_source_name(self):
+        pass
+
+    @abstractmethod
     def get_friendly_name(self):
         pass
 
@@ -82,6 +87,9 @@ class BaseAuthentication(object):
 
 class InternalAuthentication(BaseAuthentication):
 
+    def get_source_name(self):
+        return INTERNAL
+
     def get_friendly_name(self):
         return gettext("internal")
 
diff --git a/web/pgadmin/authenticate/kerberos.py b/web/pgadmin/authenticate/kerberos.py
new file mode 100644
index 000000000..629fc7bf7
--- /dev/null
+++ b/web/pgadmin/authenticate/kerberos.py
@@ -0,0 +1,138 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the Spnego/Kerberos authentication."""
+
+import base64
+import gssapi
+from os import environ
+
+from werkzeug.datastructures import Headers
+from flask_babelex import gettext
+from flask import Flask, request, Response, session,\
+    current_app, render_template, flash
+
+import config
+from pgadmin.model import User, ServerGroup, db, Role
+from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import KERBEROS
+
+from flask_security.views import _security, _commit, _ctx
+from werkzeug.datastructures import MultiDict
+
+from .internal import BaseAuthentication
+
+
+# Set the Kerberos config file
+if config.KRB_KTNAME and config.KRB_KTNAME != '<KRB5_KEYTAB_FILE>':
+    environ['KRB5_KTNAME'] = config.KRB_KTNAME
+
+
+class KerberosAuthentication(BaseAuthentication):
+
+    def get_source_name(self):
+        return KERBEROS
+
+    def get_friendly_name(self):
+        return gettext("kerberos")
+
+    def validate(self, form):
+        return True
+
+    def authenticate(self, frm):
+        retval = [True, None]
+        negotiate = False
+        headers = Headers()
+        authorization = request.headers.get("Authorization", None)
+        form_class = _security.login_form
+
+        if request.json:
+            form = form_class(MultiDict(request.json))
+        else:
+            form = form_class()
+
+        try:
+            if authorization is not None:
+                auth_header = authorization.split()
+                if auth_header[0] == 'Negotiate':
+                    status, negotiate = self.negotiate_start(auth_header[1])
+
+                    if status:
+                        # Saving the first 15 characters of the kerberos key
+                        # to encrypt/decrypt database password
+                        session['kerberos_key'] = auth_header[1][0:15]
+                        # Create user
+                        retval = self.__auto_create_user(
+                            str(negotiate.initiator_name))
+                    elif isinstance(negotiate, Exception):
+                        flash(gettext(negotiate), 'danger')
+                        retval = [status,
+                                  Response(render_template(
+                                      "security/login_user.html",
+                                      login_user_form=form))]
+                    else:
+                        headers.add('WWW-Authenticate', 'Negotiate ' +
+                                    str(base64.b64encode(negotiate), 'utf-8'))
+                        return False, Response("Success", 200, headers)
+            else:
+                flash(gettext("Kerberos authentication failed."
+                              " Couldn't find kerberos ticket."), 'danger')
+                headers.add('WWW-Authenticate', 'Negotiate')
+                retval = [False,
+                          Response(render_template(
+                              "security/login_user.html",
+                              login_user_form=form), 401, headers)]
+        finally:
+            if negotiate is not False:
+                self.negotiate_end(negotiate)
+        return retval
+
+    def negotiate_start(self, in_token):
+        svc_princ = gssapi.Name('HTTP@%s' % config.KRB_APP_HOST_NAME,
+                                name_type=gssapi.NameType.hostbased_service)
+        cname = svc_princ.canonicalize(gssapi.MechType.kerberos)
+
+        try:
+            server_creds = gssapi.Credentials(usage='accept', name=cname)
+            context = gssapi.SecurityContext(creds=server_creds)
+            out_token = context.step(base64.b64decode(in_token))
+        except Exception as e:
+            current_app.logger.exception(e)
+            return False, e
+
+        if out_token and not context.complete:
+            return False, out_token
+        if context.complete:
+            return True, context
+        else:
+            return False, None
+
+    def negotiate_end(self, context):
+        # Free gss_cred_id_t
+        del_creds = getattr(context, 'delegated_creds', None)
+        if del_creds:
+            deleg_creds = context.delegated_creds
+            del(deleg_creds)
+
+    def __auto_create_user(self, username):
+        """Add the ldap user to the internal SQLite database."""
+        username = str(username)
+        if config.KRB_AUTO_CREATE_USER:
+            user = User.query.filter_by(
+                username=username).first()
+            if user is None:
+                return create_user({
+                    'username': username,
+                    'email': username,
+                    'role': 2,
+                    'active': True,
+                    'auth_source': KERBEROS
+                })
+
+        return True, {'username': username}
diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py
index a9eca110f..2f0f61b7c 100644
--- a/web/pgadmin/authenticate/ldap.py
+++ b/web/pgadmin/authenticate/ldap.py
@@ -23,6 +23,7 @@ from .internal import BaseAuthentication
 from pgadmin.model import User, ServerGroup, db, Role
 from flask import current_app
 from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import LDAP
 
 
 ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
@@ -31,6 +32,9 @@ ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
 class LDAPAuthentication(BaseAuthentication):
     """Ldap Authentication Class"""
 
+    def get_source_name(self):
+        return LDAP
+
     def get_friendly_name(self):
         return gettext("ldap")
 
@@ -151,7 +155,7 @@ class LDAPAuthentication(BaseAuthentication):
                     'email': user_email,
                     'role': 2,
                     'active': True,
-                    'auth_source': 'ldap'
+                    'auth_source': LDAP
                 })
 
         return True, None
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 1bae28f9c..c0ad869a1 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
     generate_reset_password_token, update_password
 from flask_security.signals import reset_password_instructions_sent
 from flask_security.utils import config_value, do_flash, get_url, \
-    get_message, slash_url_suffix, login_user, send_mail
+    get_message, slash_url_suffix, login_user, send_mail, logout_user
 from flask_security.views import _security, _commit, _ctx
 from werkzeug.datastructures import MultiDict
 
@@ -47,7 +47,8 @@ from pgadmin.utils.master_password import validate_master_password, \
     set_masterpass_check_text, cleanup_master_password, get_crypt_key, \
     set_crypt_key, process_masterpass_disabled
 from pgadmin.model import User
-from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE
+from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE,\
+    INTERNAL, KERBEROS
 
 try:
     from flask_security.views import default_render_json
@@ -280,7 +281,8 @@ class BrowserModule(PgAdminModule):
                 'browser.check_master_password',
                 'browser.set_master_password',
                 'browser.reset_master_password',
-                'browser.lock_layout']
+                'browser.lock_layout'
+                ]
 
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -539,6 +541,12 @@ class BrowserPluginModule(PgAdminModule):
 
 
 def _get_logout_url():
+    if config.SERVER_MODE and\
+            session['_auth_source_manager_obj']['current_source'] == \
+            KERBEROS:
+        return '{0}?next={1}'.format(url_for(
+            'authenticate.kerberos_logout'), url_for(BROWSER_INDEX))
+
     return '{0}?next={1}'.format(
         url_for('security.logout'), url_for(BROWSER_INDEX))
 
@@ -664,13 +672,18 @@ def index():
     auth_only_internal = False
     auth_source = []
 
+    session['allow_save_password'] = True
+
     if config.SERVER_MODE:
         if len(config.AUTHENTICATION_SOURCES) == 1\
-                and 'internal' in config.AUTHENTICATION_SOURCES:
+                and INTERNAL in config.AUTHENTICATION_SOURCES:
             auth_only_internal = True
         auth_source = session['_auth_source_manager_obj'][
             'source_friendly_name']
 
+        if session['_auth_source_manager_obj']['current_source'] == KERBEROS:
+            session['allow_save_password'] = False
+
     response = Response(render_template(
         MODULE_NAME + "/index.html",
         username=current_user.username,
@@ -1086,7 +1099,7 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE:
             # Check the Authentication source of the User
             user = User.query.filter_by(
                 email=form.data['email'],
-                auth_source=current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+                auth_source=INTERNAL
             ).first()
 
             if user is None:
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index ecc1281a2..5daef8120 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -10,7 +10,7 @@
 import simplejson as json
 import pgadmin.browser.server_groups as sg
 from flask import render_template, request, make_response, jsonify, \
-    current_app, url_for
+    current_app, url_for, session
 from flask_babelex import gettext
 from flask_security import current_user, login_required
 from pgadmin.browser.server_groups.servers.types import ServerType
@@ -1822,7 +1822,13 @@ class ServerNode(PGChildNodeView):
                     _=gettext,
                     service=server.service,
                     prompt_tunnel_password=prompt_tunnel_password,
-                    prompt_password=prompt_password
+                    prompt_password=prompt_password,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
+                    allow_save_tunnel_password=True if
+                    config.ALLOW_SAVE_TUNNEL_PASSWORD and
+                    session['allow_save_password'] else False
                 )
             )
         else:
@@ -1836,6 +1842,9 @@ class ServerNode(PGChildNodeView):
                     errmsg=errmsg,
                     service=server.service,
                     _=gettext,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
                 )
             )
 
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
index 9b2c425e3..35f4e2a16 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
@@ -19,7 +19,7 @@
             <div class="col-sm-10">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
index 5de642f85..e34a257f2 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
@@ -15,7 +15,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_tunnel_password" name="save_tunnel_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_TUNNEL_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_tunnel_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_tunnel_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
@@ -39,7 +39,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/templates/browser/kerberos_login.html b/web/pgadmin/browser/templates/browser/kerberos_login.html
new file mode 100644
index 000000000..c112e3196
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_login.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Login Failed.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/templates/browser/kerberos_logout.html b/web/pgadmin/browser/templates/browser/kerberos_logout.html
new file mode 100644
index 000000000..430dc6f25
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_logout.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Logged out successfully.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/tests/test_kerberos_with_mocking.py b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
new file mode 100644
index 000000000..f87ce5521
--- /dev/null
+++ b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
@@ -0,0 +1,104 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import config as app_config
+from pgadmin.utils.route import BaseTestGenerator
+from regression.python_test_utils import test_utils as utils
+from pgadmin.authenticate.registry import AuthSourceRegistry
+from unittest.mock import patch, MagicMock
+
+
+class KerberosLoginMockTestCase(BaseTestGenerator):
+    """
+    This class checks Spnego/Kerberos login functionality by mocking
+    HTTP negotiate authentication.
+    """
+
+    scenarios = [
+        ('Spnego/Kerberos Authentication: Test Unauthorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=1
+        )),
+        ('Spnego/Kerberos Authentication: Test Authorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=2
+        ))
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        We need to logout the test client as we are testing
+        spnego/kerberos login scenarios.
+        """
+        cls.tester.logout()
+
+    def setUp(self):
+        app_config.AUTHENTICATION_SOURCES = self.auth_source
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'kerberos'
+
+    def runTest(self):
+        """This function checks spnego/kerberos login functionality."""
+        if self.flag == 1:
+            self.test_unauthorized()
+        elif self.flag == 2:
+            if app_config.SERVER_MODE is False:
+                self.skipTest(
+                    "Can not run Kerberos Authentication in the Desktop mode."
+                )
+
+            self.test_authorized()
+
+    def test_unauthorized(self):
+        """
+        Ensure that when client sends the first request,
+        the Negotiate request is sent.
+        """
+        res = self.tester.login(None, None, True)
+        self.assertEqual(res.status_code, 401)
+        self.assertEqual(res.headers.get('www-authenticate'), 'Negotiate')
+
+    def test_authorized(self):
+        """
+        Ensure that when the client sends an correct authorization token,
+        they receive a 200 OK response and the user principal is extracted and
+        passed on to the routed method.
+        """
+
+        class delCrads:
+            def __init__(self):
+                self.initiator_name = 'user@PGADMIN.ORG'
+        del_crads = delCrads()
+
+        AuthSourceRegistry.registry['kerberos'].negotiate_start = MagicMock(
+            return_value=[True, del_crads])
+        res = self.tester.login(None,
+                                None,
+                                True,
+                                headers={'Authorization': 'Negotiate CTOKEN'}
+                                )
+        self.assertEqual(res.status_code, 200)
+        respdata = 'Gravatar image for %s' % del_crads.initiator_name
+        self.assertTrue(respdata in res.data.decode('utf8'))
+
+    def tearDown(self):
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
+        self.tester.logout()
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        cls.tester.logout()
+        app_config.AUTHENTICATION_SOURCES = ['internal']
+        utils.login_tester_account(cls.tester)
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 2405a498d..05ed998c6 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -25,7 +25,7 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_json_response, bad_request, \
     internal_server_error, unauthorized
 
-from config import PG_DEFAULT_DRIVER
+from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD
 from pgadmin.model import Server, User
 from pgadmin.utils.driver import get_driver
 from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
@@ -402,6 +402,9 @@ def _init_query_tool(trans_id, connect, sgid, sid, did, **kwargs):
                             username=user,
                             errmsg=msg,
                             _=gettext,
+                            allow_save_password=True if
+                            ALLOW_SAVE_PASSWORD and
+                            session['allow_save_password'] else False,
                         )
                     ), '', ''
                 else:
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index 8641130c4..ce280a3d2 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 import re
 
 from flask import render_template, request, \
-    url_for, Response, abort, current_app
+    url_for, Response, abort, current_app, session
 from flask_babelex import gettext as _
 from flask_security import login_required, roles_required, current_user
 from flask_security.utils import encrypt_password
@@ -24,7 +24,8 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_response as ajax_response, \
     make_json_response, bad_request, internal_server_error, forbidden
 from pgadmin.utils.csrf import pgCSRFProtect
-from pgadmin.utils.constants import MIMETYPE_APP_JS
+from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL,\
+    SUPPORTED_AUTH_SOURCES, KERBEROS
 from pgadmin.utils.validation_utils import validate_email
 from pgadmin.model import db, Role, User, UserPreference, Server, \
     ServerGroup, Process, Setting
@@ -167,11 +168,13 @@ def current_user_info():
                 config.SERVER_MODE is True
                 else 'postgres'
             ),
-            allow_save_password='true' if config.ALLOW_SAVE_PASSWORD
+            allow_save_password='true' if
+            config.ALLOW_SAVE_PASSWORD and session['allow_save_password']
             else 'false',
-            allow_save_tunnel_password='true'
-            if config.ALLOW_SAVE_TUNNEL_PASSWORD else 'false',
-            auth_sources=config.AUTHENTICATION_SOURCES,
+            allow_save_tunnel_password='true' if
+            config.ALLOW_SAVE_TUNNEL_PASSWORD and session[
+                'allow_save_password'] else 'false',
+            auth_sources=config.AUTHENTICATION_SOURCES
         ),
         status=200,
         mimetype=MIMETYPE_APP_JS
@@ -254,10 +257,10 @@ def _create_new_user(new_data):
     :return: Return new created user.
     """
     auth_source = new_data['auth_source'] if 'auth_source' in new_data \
-        else current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+        else INTERNAL
     username = new_data['username'] if \
         'username' in new_data and auth_source != \
-        current_app.PGADMIN_DEFAULT_AUTH_SOURCE else new_data['email']
+        INTERNAL else new_data['email']
     email = new_data['email'] if 'email' in new_data else None
     password = new_data['password'] if 'password' in new_data else None
 
@@ -279,7 +282,7 @@ def _create_new_user(new_data):
 
 def create_user(data):
     if 'auth_source' in data and data['auth_source'] != \
-            current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+            INTERNAL:
         req_params = ('username', 'role', 'active', 'auth_source')
     else:
         req_params = ('email', 'role', 'active', 'newPassword',
@@ -380,7 +383,7 @@ def update(uid):
     )
 
     # Username and email can not be changed for internal users
-    if usr.auth_source == current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+    if usr.auth_source == INTERNAL:
         non_editable_params = ('username', 'email')
 
         for f in non_editable_params:
@@ -463,7 +466,7 @@ def role(rid):
 )
 def auth_sources():
     sources = []
-    for source in current_app.PGADMIN_SUPPORTED_AUTH_SOURCE:
+    for source in SUPPORTED_AUTH_SOURCES:
         sources.append({'label': source, 'value': source})
 
     return ajax_response(
diff --git a/web/pgadmin/utils/constants.py b/web/pgadmin/utils/constants.py
index 0a2261f05..5fd942304 100644
--- a/web/pgadmin/utils/constants.py
+++ b/web/pgadmin/utils/constants.py
@@ -47,3 +47,12 @@ ERROR_FETCHING_ROLE_INFORMATION = gettext(
     'Error fetching role information from the database server.')
 
 ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
+
+# Authentication Sources
+INTERNAL = 'internal'
+LDAP = 'ldap'
+KERBEROS = 'kerberos'
+
+SUPPORTED_AUTH_SOURCES = [INTERNAL,
+                          LDAP,
+                          KERBEROS]
diff --git a/web/pgadmin/utils/master_password.py b/web/pgadmin/utils/master_password.py
index 759bf36e0..629eec941 100644
--- a/web/pgadmin/utils/master_password.py
+++ b/web/pgadmin/utils/master_password.py
@@ -1,8 +1,9 @@
 import config
-from flask import current_app
+from flask import current_app, session
 from flask_login import current_user
 from pgadmin.model import db, User, Server
 from pgadmin.utils.crypto import encrypt, decrypt
+from pgadmin.utils.constants import KERBEROS
 
 
 MASTERPASS_CHECK_TEXT = 'ideas are bulletproof'
@@ -32,6 +33,11 @@ def get_crypt_key():
     elif config.MASTER_PASSWORD_REQUIRED \
             and not config.SERVER_MODE and enc_key is None:
         return False, None
+    elif config.SERVER_MODE and \
+            session['_auth_source_manager_obj']['source_friendly_name']\
+            == KERBEROS:
+        return True, session['kerberos_key'] if 'kerberos_key' in session \
+            else None
     else:
         return True, enc_key
 
diff --git a/web/regression/python_test_utils/csrf_test_client.py b/web/regression/python_test_utils/csrf_test_client.py
index 11d2cfca5..ca4120e18 100644
--- a/web/regression/python_test_utils/csrf_test_client.py
+++ b/web/regression/python_test_utils/csrf_test_client.py
@@ -101,7 +101,8 @@ class TestClient(testing.FlaskClient):
 
             return csrf_token
 
-    def login(self, email, password, _follow_redirects=False):
+    def login(self, email, password, _follow_redirects=False,
+              headers=None):
         if config.SERVER_MODE is True:
             res = self.get('/login', follow_redirects=True)
             csrf_token = self.fetch_csrf(res)
@@ -113,7 +114,8 @@ class TestClient(testing.FlaskClient):
                 email=email, password=password,
                 csrf_token=csrf_token,
             ),
-            follow_redirects=_follow_redirects
+            follow_redirects=_follow_redirects,
+            headers=headers
         )
         self.csrf_token = csrf_token
 
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 3328ed3f6..9b794e41f 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -117,9 +117,9 @@ if config.SERVER_MODE is True:
 app.config['WTF_CSRF_ENABLED'] = True
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
 app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
 
+
 app.test_client_class = TestClient
 test_client = app.test_client()
 test_client.setApp(app)
