diff --git a/docs/en_US/images/role_membership.png b/docs/en_US/images/role_membership.png
index 9c42c83e1b1c3ee2de181dc907b1999f3ca3e4bd..c1e07fee9000a0101c21d57e65fd43a2f9ca2ae9 100644
GIT binary patch
diff --git a/docs/en_US/role_dialog.rst b/docs/en_US/role_dialog.rst
index 9cb1c1f7..bf14dd25 100644
--- a/docs/en_US/role_dialog.rst
+++ b/docs/en_US/role_dialog.rst
@@ -71,7 +71,7 @@ Use the *Privileges* tab to grant privileges to the role.
     :alt: Role dialog membership tab
     :align: center
 
-* Specify members of the role in the *Role Membership* field. Click inside the
+* Specify member of the role in the *Member of* field and specify the members in the *Member* field. Click inside the
   *Roles* field to select role names from a drop down list. Confirm each
   selection by checking the checkbox to the right of the role name; delete a
   selection by clicking the *x* to the left of the role name. Membership conveys
diff --git a/web/pgadmin/browser/server_groups/servers/roles/__init__.py b/web/pgadmin/browser/server_groups/servers/roles/__init__.py
index ca08b979..28fe6be2 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/roles/__init__.py
@@ -236,6 +236,105 @@ class RoleView(PGChildNodeView):
                 data['rolmembership'].get('deleted', []),
                 lambda _: True, 'role')
 
+    def _process_rolmembers(self, id, data):
+        """
+        Parser role members.
+        :param id:
+        :param data:
+        """
+        def _part_dict_list(dict_list, condition, list_key=None):
+            ret_val = []
+            for d in dict_list:
+                if condition(d):
+                    ret_val.append(d[list_key])
+
+            return ret_val
+        if id == -1:
+            data['rol_members'] = []
+            data['rol_admins'] = []
+
+            data['rol_admins'] = _part_dict_list(
+                data['rolmembers'], lambda d: d['admin'], 'role')
+            data['rol_members'] = _part_dict_list(
+                data['rolmembers'], lambda d: not d['admin'], 'role')
+        else:
+            data['rol_admins'] = _part_dict_list(
+                data['rolmembers'].get('added', []),
+                lambda d: d['admin'], 'role')
+            data['rol_members'] = _part_dict_list(
+                data['rolmembers'].get('added', []),
+                lambda d: not d['admin'], 'role')
+
+            data['rol_admins'].extend(_part_dict_list(
+                data['rolmembers'].get('changed', []),
+                lambda d: d['admin'], 'role'))
+            data['rol_revoked_admins'] = _part_dict_list(
+                data['rolmembers'].get('changed', []),
+                lambda d: not d['admin'], 'role')
+
+            data['rol_revoked'] = _part_dict_list(
+                data['rolmembers'].get('deleted', []),
+                lambda _: True, 'role')
+
+    def _validate_rolemembers(self, id, data):
+        """
+        Validate the rolmembers data dict
+        :param data: role data
+        :return: valid or invalid message
+        """
+        if 'rolmembers' not in data:
+            return None
+
+        if id == -1:
+            msg = _("""
+Role members information must be passed as an array of JSON objects in the
+following format:
+
+rolmembers:[{
+    role: [rolename],
+    admin: True/False
+    },
+    ...
+]""")
+
+            if not self._validate_input_dict_for_new(data['rolmembers'],
+                                                     ['role', 'admin']):
+                return msg
+
+            self._process_rolmembers(id, data)
+            return None
+
+        msg = _("""
+Role membership information must be passed as a string representing an array of
+JSON objects in the following format:
+rolmembers:{
+    'added': [{
+        role: [rolename],
+        admin: True/False
+        },
+        ...
+        ],
+    'deleted': [{
+        role: [rolename],
+        admin: True/False
+        },
+        ...
+        ],
+    'updated': [{
+        role: [rolename],
+        admin: True/False
+        },
+        ...
+        ]
+""")
+        if not self._validate_input_dict_for_update(data['rolmembers'],
+                                                    ['role', 'admin'],
+                                                    ['role']):
+            return msg
+
+        self._process_rolmembers(id, data)
+        return None
+
     def _validate_rolemembership(self, id, data):
         """
         Validate the rolmembership data dict
@@ -433,7 +532,7 @@ rolmembership:{
                         'rolcanlogin', 'rolsuper', 'rolcreatedb',
                         'rolcreaterole', 'rolinherit', 'rolreplication',
                         'rolcatupdate', 'variables', 'rolmembership',
-                        'seclabels'
+                        'seclabels', 'rolmembers'
                     ]:
                         data[key] = json.loads(val, encoding='utf-8')
                     else:
@@ -466,6 +565,11 @@ rolmembership:{
             if invalid_msg is not None:
                 return precondition_required(invalid_msg)
 
+            invalid_msg = self._validate_rolemembers(
+                kwargs.get('rid', -1), data)
+            if invalid_msg is not None:
+                return precondition_required(invalid_msg)
+
             self.request = data
 
             return f(self, **kwargs)
@@ -716,6 +820,16 @@ rolmembership:{
                     })
                 row['seclabels'] = res
 
+            if 'rolmembers' in row:
+                rolmembers = []
+                for role in row['rolmembers']:
+                    role = re.search(r'([01])(.+)', role)
+                    rolmembers.append({
+                        'role': role.group(2),
+                        'admin': True if role.group(1) == '1' else False
+                    })
+                row['rolmembers'] = rolmembers
+
     @check_precondition(action='properties')
     def properties(self, gid, sid, rid):
 
diff --git a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js
index 6c382854..9bfc2b26 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js
+++ b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.js
@@ -90,7 +90,7 @@ define('pgadmin.node.role', [
     template: _.template([
       '<label class="<%=Backform.controlLabelClassName%>"><%=label%></label>',
       '<div class="<%=Backform.controlsClassName%>">',
-      '  <select title = <%=label%> multiple="multiple" style="width:100%;" class="pgadmin-controls <%=extraClasses.join(\' \')%>" name="<%=name%>" value="<%-JSON.stringify(value)%>" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%>>',
+      '  <select title = <%=label%> multiple="multiple" style="width:100%;" class="pgadmin-controls <%=extraClasses.join(\' \')%>" name="<%=name%>" value="<%-JSON.stringify(value)%>" <%=disabled ? "disabled" : ""%> <%=readonly ? "readonly" : ""%> <%=required ? "required" : ""%>>',
       '    <% for (var i=0; i < options.length; i++) { %>',
       '      <% var option = options[i]; %>',
       '      <option value=<%-option.value%> data-icon=<%-option.image%> <%=value != null && _.indexOf(value, option.value) != -1 ? "selected" : ""%> <%=option.disabled ? "disabled=\'disabled\'" : ""%>><%-option.label%></option>',
@@ -107,7 +107,7 @@ define('pgadmin.node.role', [
       '  <span><%= opttext %><span>',
       '  <% if (checkbox) { %>',
       '  <div class="custom-control custom-checkbox custom-checkbox-no-label d-inline">',
-      '    <input tabindex="-1" type="checkbox" class="custom-control-input" id="check_<%= opttext %>" />',
+      '    <input tabindex="-1" type="checkbox" class="custom-control-input" id="check_<%= opttext %>" <%=disabled ? "disabled" : ""%> />',
       '    <label class="custom-control-label" for="check_<%= opttext %>">',
       '      <span class="sr-only">WITH ADMIN<span>',
       '    </label>',
@@ -149,6 +149,7 @@ define('pgadmin.node.role', [
       _.extend(data, {
         disabled: evalF(data.disabled, data, this.model),
         visible:  evalF(data.visible, data, this.model),
+        readonly: evalF(data.readonly, data, this.model),
         required: evalF(data.required, data, this.model),
         helpMessage: evalASFunc(data.helpMessage, data, this.model),
       });
@@ -242,7 +243,7 @@ define('pgadmin.node.role', [
         multiple: true,
         tags: true,
         allowClear: data.disabled ? false : true,
-        placeholder: data.disabled ? '' : gettext('Select members'),
+        placeholder: data.disabled ? '' : gettext('Select roles'),
         width: 'style',
       }).on('change', function(e) {
         $(e.target).find(':selected').each(function() {
@@ -386,6 +387,7 @@ define('pgadmin.node.role', [
           rolcatupdate: false,
           rolreplication: false,
           rolmembership: [],
+          rolmembers: [],
           rolvaliduntil: null,
           seclabels: [],
           variables: [],
@@ -492,11 +494,12 @@ define('pgadmin.node.role', [
           controlsClassName: 'pgadmin-controls pg-el-sm-8 pg-el-12',
           min_version: 90100,
           readonly: 'readonly',
-        },{
-          id: 'rolmembership', label: gettext('Roles'),
+        },
+        {
+          id: 'rolmembership', label: gettext('Member of'),
           group: gettext('Membership'), type: 'collection',
-          cell: 'string', readonly: 'readonly',
-          mode: ['properties', 'edit', 'create'],
+          cell: 'string', mode: ['properties', 'edit', 'create'],
+          readonly: 'readonly',
           control: RoleMembersControl, model: pgBrowser.Node.Model.extend({
             keys: ['role'],
             idAttribute: 'role',
@@ -518,7 +521,34 @@ define('pgadmin.node.role', [
               return gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.');
             }
           },
-        },{
+        },
+        {
+          id: 'rolmembers', label: gettext('Members'), type: 'collection', group: gettext('Membership'),
+          mode: ['properties', 'edit', 'create'], cell: 'string',
+          readonly: 'readonly',
+          control: RoleMembersControl, model: pgBrowser.Node.Model.extend({
+            keys: ['role'],
+            idAttribute: 'role',
+            defaults: {
+              role: undefined,
+              admin: false,
+            },
+            validate: function() {
+              return null;
+            },
+          }),
+          filter: function(d) {
+            return this.model.isNew() || (this.model.get('rolname') != d.label);
+          },
+          helpMessage: function(m) {
+            if (m.has('read_only') && m.get('read_only') == false) {
+              return gettext('Select the checkbox for roles to include WITH ADMIN OPTION.');
+            } else {
+              return gettext('Roles shown with a check mark have the WITH ADMIN OPTION set.');
+            }
+          },
+        },
+        {
           id: 'variables', label: '', type: 'collection',
           group: gettext('Parameters'), hasDatabase: true, url: 'variables',
           model: pgBrowser.Node.VariableModel.extend({keys:['name', 'database']}),
diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/properties.sql
index d7d90dd2..2e653746 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/properties.sql
+++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/properties.sql
@@ -9,6 +9,15 @@ SELECT
 			LEFT JOIN pg_catalog.pg_roles rm ON (rm.oid = am.roleid)
 	) rolmembership,
 	(SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_shseclabel sl1 WHERE sl1.objoid=r.oid) AS seclabels
+    {% if rid %}
+        ,ARRAY(
+           SELECT
+				CASE WHEN pg.admin_option THEN '1' ELSE '0' END || pg.usename
+			FROM
+				(SELECT pg_roles.rolname AS usename, pg_auth_members.admin_option AS admin_option FROM pg_roles
+				JOIN pg_auth_members ON pg_roles.oid=pg_auth_members.member AND pg_auth_members.roleid={{ rid|qtLiteral }}::oid) pg
+        ) rolmembers
+    {% endif %}
 FROM
 	pg_catalog.pg_roles r
 {% if rid %}
diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/update.sql
index b23593c4..68434207 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.1_plus/update.sql
@@ -124,3 +124,15 @@ GRANT {{ conn|qtIdent(data.members)|join(', ') }} TO {{ conn|qtIdent(rolname) }}
 
 COMMENT ON ROLE {{ conn|qtIdent(rolname) }} IS {{ data.description|qtLiteral }};
 {% endif %}
+
+{% if 'rol_revoked_admins' in data and
+	data.rol_revoked_admins|length > 0
+%}
+
+REVOKE ADMIN OPTION FOR {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked_admins)|join(', ') }};{% endif %}{% if 'rol_revoked' in data and data.rol_revoked|length > 0 %}
+
+REVOKE {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked)|join(', ') }};{% endif %}{% if data.rol_admins and data.rol_admins|length > 0 %}
+
+GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_admins)|join(', ') }} WITH ADMIN OPTION;{% endif %}{% if data.rol_members and data.rol_members|length > 0 %}
+
+GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_members)|join(', ') }};{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/properties.sql
index 0f07798a..8e7091b7 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/properties.sql
+++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/properties.sql
@@ -10,6 +10,15 @@ SELECT
 		ORDER BY rm.rolname
 	) AS rolmembership,
 	(SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_shseclabel sl1 WHERE sl1.objoid=r.oid) AS seclabels
+	{% if rid %}
+        ,ARRAY(
+           SELECT
+				CASE WHEN pg.admin_option THEN '1' ELSE '0' END || pg.usename
+			FROM
+				(SELECT pg_roles.rolname AS usename, pg_auth_members.admin_option AS admin_option FROM pg_roles
+				JOIN pg_auth_members ON pg_roles.oid=pg_auth_members.member AND pg_auth_members.roleid={{ rid|qtLiteral }}::oid) pg
+        ) rolmembers
+    {% endif %}
 FROM
 	pg_catalog.pg_roles r
 {% if rid %}
diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/update.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/update.sql
index f77921f5..7a234ef1 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/update.sql
+++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/9.4_plus/update.sql
@@ -99,3 +99,15 @@ GRANT {{ conn|qtIdent(data.members)|join(', ') }} TO {{ conn|qtIdent(rolname) }}
 
 COMMENT ON ROLE {{ conn|qtIdent(rolname) }} IS {{ data.description|qtLiteral }};
 {% endif %}
+
+{% if 'rol_revoked_admins' in data and
+	data.rol_revoked_admins|length > 0
+%}
+
+REVOKE ADMIN OPTION FOR {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked_admins)|join(', ') }};{% endif %}{% if 'rol_revoked' in data and data.rol_revoked|length > 0 %}
+
+REVOKE {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked)|join(', ') }};{% endif %}{% if data.rol_admins and data.rol_admins|length > 0 %}
+
+GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_admins)|join(', ') }} WITH ADMIN OPTION;{% endif %}{% if data.rol_members and data.rol_members|length > 0 %}
+
+GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_members)|join(', ') }};{% endif %}
diff --git a/web/pgadmin/static/scss/_select2.overrides.scss b/web/pgadmin/static/scss/_select2.overrides.scss
index c17225b5..0f87c403 100644
--- a/web/pgadmin/static/scss/_select2.overrides.scss
+++ b/web/pgadmin/static/scss/_select2.overrides.scss
@@ -117,7 +117,8 @@ select[readonly].select2-hidden-accessible + .select2-container {
 }
 
 select[readonly].select2-hidden-accessible + .select2-container .select2-selection {
-    background: #eee;
+    background: $select2-readonly;
+    color: $text-muted;
     box-shadow: none;
 }
 
diff --git a/web/pgadmin/static/scss/resources/_default.variables.scss b/web/pgadmin/static/scss/resources/_default.variables.scss
index 1e357b31..ce33424e 100644
--- a/web/pgadmin/static/scss/resources/_default.variables.scss
+++ b/web/pgadmin/static/scss/resources/_default.variables.scss
@@ -369,3 +369,5 @@ $erd-link-selected-color: $color-fg !default;
   @return '%23' + str-slice('#{$colour}', 2, -1)
 }
 $erd-bg-grid: url("data:image/svg+xml, %3Csvg width='100%25' viewBox='0 0 45 45' style='background-color:#{url-friendly-colour($erd-canvas-bg)}' height='100%25' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern id='smallGrid' width='15' height='15' patternUnits='userSpaceOnUse'%3E%3Cpath d='M 15 0 L 0 0 0 15' fill='none' stroke='#{url-friendly-colour($erd-canvas-grid)}' stroke-width='0.5'/%3E%3C/pattern%3E%3Cpattern id='grid' width='45' height='45' patternUnits='userSpaceOnUse'%3E%3Crect width='100' height='100' fill='url(%23smallGrid)'/%3E%3Cpath d='M 100 0 L 0 0 0 100' fill='none' stroke='#{url-friendly-colour($erd-canvas-grid)}' stroke-width='1'/%3E%3C/pattern%3E%3C/defs%3E%3Crect width='100%25' height='100%25' fill='url(%23grid)' /%3E%3C/svg%3E%0A");
+
+$select2-readonly: $color-gray-lighter !default;
diff --git a/web/pgadmin/static/scss/resources/dark/_theme.variables.scss b/web/pgadmin/static/scss/resources/dark/_theme.variables.scss
index 6912060b..4605b0fc 100644
--- a/web/pgadmin/static/scss/resources/dark/_theme.variables.scss
+++ b/web/pgadmin/static/scss/resources/dark/_theme.variables.scss
@@ -134,3 +134,5 @@ $erd-canvas-bg: $color-gray-light;
 $erd-canvas-grid: #444952;
 $erd-link-color: $color-fg;
 $erd-link-selected-color: $color-fg;
+
+$select2-readonly: $color-bg;
diff --git a/web/pgadmin/static/scss/resources/high_contrast/_theme.variables.scss b/web/pgadmin/static/scss/resources/high_contrast/_theme.variables.scss
index 2d26af1f..65d80cbc 100644
--- a/web/pgadmin/static/scss/resources/high_contrast/_theme.variables.scss
+++ b/web/pgadmin/static/scss/resources/high_contrast/_theme.variables.scss
@@ -205,3 +205,5 @@ $span-text-color: #9D9FA1 !default;
 $span-text-color-hover: $black !default;
 $quick-search-a-text-color: $black !default;
 $quick-search-info-icon: #8A8A8A !default;
+
+$select2-readonly: $color-gray;
