diff --git a/lib/ansible/modules/network/netscaler/netscaler_cs_vserver.py b/lib/ansible/modules/network/netscaler/netscaler_cs_vserver.py
index a105ce87a96..611be345f00 100644
--- a/lib/ansible/modules/network/netscaler/netscaler_cs_vserver.py
+++ b/lib/ansible/modules/network/netscaler/netscaler_cs_vserver.py
@@ -500,6 +500,19 @@ options:
             - "."
             - "Minimum value = C(1)"
 
+    lbvserver:
+        description:
+            - The default Load Balancing virtual server.
+        version_added: "2.5"
+
+    ssl_certkey:
+        description:
+            - The name of the ssl certificate that is bound to this service.
+            - The ssl certificate must already exist.
+            - Creating the certificate can be done with the M(netscaler_ssl_certkey) module.
+            - This option is only applicable only when C(servicetype) is C(SSL).
+        version_added: "2.5"
+
     disabled:
         description:
             - When set to C(yes) the cs vserver will be disabled.
@@ -570,6 +583,7 @@ from ansible.module_utils.network.netscaler.netscaler import (
 )
 try:
     from nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver import csvserver
+    from nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_lbvserver_binding import csvserver_lbvserver_binding
     from nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_cspolicy_binding import csvserver_cspolicy_binding
     from nssrc.com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding import sslvserver_sslcertkey_binding
     from nssrc.com.citrix.netscaler.nitro.exception.nitro_exception import nitro_exception
@@ -624,6 +638,75 @@ def get_configured_policybindings(client, module):
     return bindings
 
 
+def get_default_lb_vserver(client, module):
+    try:
+        default_lb_vserver = csvserver_lbvserver_binding.get(client, module.params['name'])
+        return default_lb_vserver[0]
+    except nitro_exception as e:
+        if e.errorcode == 258:
+            return csvserver_lbvserver_binding()
+        else:
+            raise
+
+
+def default_lb_vserver_identical(client, module):
+    d = get_default_lb_vserver(client, module)
+    configured = ConfigProxy(
+        actual=csvserver_lbvserver_binding(),
+        client=client,
+        readwrite_attrs=[
+            'name',
+            'lbvserver',
+        ],
+        attribute_values_dict={
+            'name': module.params['name'],
+            'lbvserver': module.params['lbvserver'],
+        }
+    )
+    log('default lb vserver %s' % ((d.name, d.lbvserver),))
+    if d.name is None and module.params['lbvserver'] is None:
+        log('Default lb vserver identical missing')
+        return True
+    elif d.name is not None and module.params['lbvserver'] is None:
+        log('Default lb vserver needs removing')
+        return False
+    elif configured.has_equal_attributes(d):
+        log('Default lb vserver identical')
+        return True
+    else:
+        log('Default lb vserver not identical')
+        return False
+
+
+def sync_default_lb_vserver(client, module):
+    d = get_default_lb_vserver(client, module)
+
+    if module.params['lbvserver'] is not None:
+        configured = ConfigProxy(
+            actual=csvserver_lbvserver_binding(),
+            client=client,
+            readwrite_attrs=[
+                'name',
+                'lbvserver',
+            ],
+            attribute_values_dict={
+                'name': module.params['name'],
+                'lbvserver': module.params['lbvserver'],
+            }
+        )
+
+        if not configured.has_equal_attributes(d):
+            if d.name is not None:
+                log('Deleting default lb vserver %s' % d.lbvserver)
+                csvserver_lbvserver_binding.delete(client, d)
+            log('Adding default lb vserver %s' % configured.lbvserver)
+            configured.add()
+    else:
+        if d.name is not None:
+            log('Deleting default lb vserver %s' % d.lbvserver)
+            csvserver_lbvserver_binding.delete(client, d)
+
+
 def get_actual_policybindings(client, module):
     log('Getting actual policy bindigs')
     bindings = {}
@@ -949,6 +1032,7 @@ def main():
             type='bool',
             default=False
         ),
+        lbvserver=dict(type='str'),
     )
 
     argument_spec = dict()
@@ -1168,6 +1252,12 @@ def main():
 
                     module_result['changed'] = True
 
+            # Check default lb vserver
+            if not default_lb_vserver_identical(client, module):
+                if not module.check_mode:
+                    sync_default_lb_vserver(client, module)
+                module_result['changed'] = True
+
             if not module.check_mode:
                 res = do_state_change(client, module, csvserver_proxy)
                 if res.errorcode != 0:
diff --git a/lib/ansible/modules/network/netscaler/netscaler_server.py b/lib/ansible/modules/network/netscaler/netscaler_server.py
index 7e07c1661a5..5b5a7bf1f7a 100644
--- a/lib/ansible/modules/network/netscaler/netscaler_server.py
+++ b/lib/ansible/modules/network/netscaler/netscaler_server.py
@@ -87,6 +87,21 @@ options:
             - "Minimum value = C(0)"
             - "Maximum value = C(4094)"
 
+    graceful:
+        description:
+            - >-
+                Shut down gracefully, without accepting any new connections, and disabling each service when all of
+                its connections are closed.
+            - This option is meaningful only when setting the I(disabled) option to C(true)
+        type: bool
+        version_added: "2.5"
+
+    delay:
+        description:
+            - Time, in seconds, after which all the services configured on the server are disabled.
+            - This option is meaningful only when setting the I(disabled) option to C(true)
+        version_added: "2.5"
+
     disabled:
         description:
             - When set to C(true) the server state will be set to C(disabled).
@@ -160,8 +175,15 @@ def server_identical(client, module, server_proxy):
     log('Checking if configured server is identical')
     if server.count_filtered(client, 'name:%s' % module.params['name']) == 0:
         return False
-    server_list = server.get_filtered(client, 'name:%s' % module.params['name'])
-    if server_proxy.has_equal_attributes(server_list[0]):
+    diff = diff_list(client, module, server_proxy)
+
+    # Remove options that are not present in nitro server object
+    # These are special options relevant to the disabled action
+    for option in ['graceful', 'delay']:
+        if option in diff:
+            del diff[option]
+
+    if diff == {}:
         return True
     else:
         return False
@@ -197,6 +219,8 @@ def main():
         ),
         comment=dict(type='str'),
         td=dict(type='float'),
+        graceful=dict(type='bool'),
+        delay=dict(type='float')
     )
 
     hand_inserted_arguments = dict(
@@ -251,6 +275,8 @@ def main():
         'translationmask',
         'domainresolveretry',
         'ipv6address',
+        'graceful',
+        'delay',
         'comment',
         'td',
     ]
@@ -289,6 +315,7 @@ def main():
     ]
 
     transforms = {
+        'graceful': ['bool_yes_no'],
         'ipv6address': ['bool_yes_no'],
     }
 
diff --git a/lib/ansible/modules/network/netscaler/netscaler_servicegroup.py b/lib/ansible/modules/network/netscaler/netscaler_servicegroup.py
index f913d3bc21e..0965937faa5 100644
--- a/lib/ansible/modules/network/netscaler/netscaler_servicegroup.py
+++ b/lib/ansible/modules/network/netscaler/netscaler_servicegroup.py
@@ -271,6 +271,12 @@ options:
                     - Server port number.
                     - Range C(1) - C(65535)
                     - "* in CLI is represented as 65535 in NITRO API"
+            state:
+                choices:
+                    - 'enabled'
+                    - 'disabled'
+                description:
+                    - Initial state of the service after binding.
             hashid:
                 description:
                     - The hash identifier for the service.
@@ -427,6 +433,7 @@ def get_configured_service_members(client, module):
         'servicegroupname',
         'ip',
         'port',
+        'state',
         'hashid',
         'serverid',
         'servername',
@@ -460,8 +467,7 @@ def get_configured_service_members(client, module):
     return members
 
 
-def servicemembers_identical(client, module):
-    log('servicemembers_identical')
+def get_actual_service_members(client, module):
     try:
         # count() raises nitro exception instead of returning 0
         count = servicegroup_servicegroupmember_binding.count(client, module.params['servicegroupname'])
@@ -474,7 +480,13 @@ def servicemembers_identical(client, module):
             servicegroup_members = []
         else:
             raise
+    return servicegroup_members
 
+
+def servicemembers_identical(client, module):
+    log('servicemembers_identical')
+
+    servicegroup_members = get_actual_service_members(client, module)
     log('servicemembers %s' % servicegroup_members)
     module_servicegroups = get_configured_service_members(client, module)
     log('Number of service group members %s' % len(servicegroup_members))
@@ -497,33 +509,55 @@ def servicemembers_identical(client, module):
 
 def sync_service_members(client, module):
     log('sync_service_members')
-    delete_all_servicegroup_members(client, module)
+    configured_service_members = get_configured_service_members(client, module)
+    actual_service_members = get_actual_service_members(client, module)
+    skip_add = []
+    skip_delete = []
 
-    for member in get_configured_service_members(client, module):
-        member.add()
+    # Find positions of identical service members
+    for (configured_index, configured_service) in enumerate(configured_service_members):
+        for (actual_index, actual_service) in enumerate(actual_service_members):
+            if configured_service.has_equal_attributes(actual_service):
+                skip_add.append(configured_index)
+                skip_delete.append(actual_index)
 
+    # Delete actual that are not identical to any configured
+    for (actual_index, actual_service) in enumerate(actual_service_members):
+        # Skip identical
+        if actual_index in skip_delete:
+            log('Skipping actual delete at index %s' % actual_index)
+            continue
 
-def delete_all_servicegroup_members(client, module):
-    log('delete_all_servicegroup_members')
-    if servicegroup_servicegroupmember_binding.count(client, module.params['servicegroupname']) == 0:
-        return
-    servicegroup_members = servicegroup_servicegroupmember_binding.get(client, module.params['servicegroupname'])
-    log('len %s' % len(servicegroup_members))
-    log('count %s' % servicegroup_servicegroupmember_binding.count(client, module.params['servicegroupname']))
-    for member in servicegroup_members:
-        log('%s' % dir(member))
-        log('ip %s' % member.ip)
-        log('servername %s' % member.servername)
+        # Fallthrouth to deletion
         if all([
-            hasattr(member, 'ip'),
-            member.ip is not None,
-            hasattr(member, 'servername'),
-            member.servername is not None,
+            hasattr(actual_service, 'ip'),
+            actual_service.ip is not None,
+            hasattr(actual_service, 'servername'),
+            actual_service.servername is not None,
         ]):
-            member.ip = None
+            actual_service.ip = None
 
-        member.servicegroupname = module.params['servicegroupname']
-        servicegroup_servicegroupmember_binding.delete(client, member)
+        actual_service.servicegroupname = module.params['servicegroupname']
+        servicegroup_servicegroupmember_binding.delete(client, actual_service)
+
+    # Add configured that are not already present in actual
+    for (configured_index, configured_service) in enumerate(configured_service_members):
+
+        # Skip identical
+        if configured_index in skip_add:
+            log('Skipping configured add at index %s' % configured_index)
+            continue
+
+        # Fallthrough to addition
+        configured_service.add()
+
+
+def monitor_binding_equal(configured, actual):
+    if any([configured.monitorname != actual.monitor_name,
+            configured.servicegroupname != actual.servicegroupname,
+            configured.weight != float(actual.weight)]):
+        return False
+    return True
 
 
 def get_configured_monitor_bindings(client, module):
@@ -593,11 +627,13 @@ def monitor_bindings_identical(client, module):
     # Compare key to key
     for key in configured_key_set:
         configured_proxy = configured_bindings[key]
+
+        # Follow nscli convention for missing weight value
+        if not hasattr(configured_proxy, 'weight'):
+            configured_proxy.weight = 1
         log('configured_proxy %s' % [configured_proxy.monitorname, configured_proxy.servicegroupname, configured_proxy.weight])
         log('actual_bindings %s' % [actual_bindings[key].monitor_name, actual_bindings[key].servicegroupname, actual_bindings[key].weight])
-        if any([configured_proxy.monitorname != actual_bindings[key].monitor_name,
-                configured_proxy.servicegroupname != actual_bindings[key].servicegroupname,
-                configured_proxy.weight != float(actual_bindings[key].weight)]):
+        if not monitor_binding_equal(configured_proxy, actual_bindings[key]):
             return False
 
     # Fallthrought to success
@@ -606,8 +642,23 @@ def monitor_bindings_identical(client, module):
 
 def sync_monitor_bindings(client, module):
     log('Entering sync_monitor_bindings')
-    # Delete existing bindings
-    for binding in get_actual_monitor_bindings(client, module).values():
+
+    actual_bindings = get_actual_monitor_bindings(client, module)
+
+    # Exclude default monitors from deletion
+    for monitorname in ('tcp-default', 'ping-default'):
+        if monitorname in actual_bindings:
+            del actual_bindings[monitorname]
+
+    configured_bindings = get_configured_monitor_bindings(client, module)
+
+    to_remove = list(set(actual_bindings.keys()) - set(configured_bindings.keys()))
+    to_add = list(set(configured_bindings.keys()) - set(actual_bindings.keys()))
+    to_modify = list(set(configured_bindings.keys()) & set(actual_bindings.keys()))
+
+    # Delete existing and modifiable bindings
+    for key in to_remove + to_modify:
+        binding = actual_bindings[key]
         b = lbmonitor_servicegroup_binding()
         b.monitorname = binding.monitor_name
         b.servicegroupname = module.params['servicegroupname']
@@ -616,9 +667,9 @@ def sync_monitor_bindings(client, module):
             continue
         lbmonitor_servicegroup_binding.delete(client, b)
 
-    # Apply configured bindings
-
-    for binding in get_configured_monitor_bindings(client, module).values():
+    # Add new and modified bindings
+    for key in to_add + to_modify:
+        binding = configured_bindings[key]
         log('Adding %s' % binding.monitorname)
         binding.add()
 
diff --git a/test/units/modules/network/netscaler/test_netscaler_cs_vserver.py b/test/units/modules/network/netscaler/test_netscaler_cs_vserver.py
index 6c7927850c0..d586cc45a2b 100644
--- a/test/units/modules/network/netscaler/test_netscaler_cs_vserver.py
+++ b/test/units/modules/network/netscaler/test_netscaler_cs_vserver.py
@@ -45,6 +45,8 @@ class TestNetscalerCSVserverModule(TestModule):
             'nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver.csvserver': m,
             'nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_cspolicy_binding': m,
             'nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_cspolicy_binding.csvserver_cspolicy_binding': m,
+            'nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_lbvserver_binding': m,
+            'nssrc.com.citrix.netscaler.nitro.resource.config.cs.csvserver_lbvserver_binding.csvserver_lbvserver_binding': m,
             'nssrc.com.citrix.netscaler.nitro.resource.config.ssl': m,
             'nssrc.com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding': m,
             'nssrc.com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding.sslvserver_sslcertkey_binding': m,
diff --git a/test/units/modules/network/netscaler/test_netscaler_server.py b/test/units/modules/network/netscaler/test_netscaler_server.py
index 32aafb4072d..237a56b2ffc 100644
--- a/test/units/modules/network/netscaler/test_netscaler_server.py
+++ b/test/units/modules/network/netscaler/test_netscaler_server.py
@@ -177,6 +177,7 @@ class TestNetscalerServerModule(TestModule):
             get_nitro_client=m,
             server_exists=Mock(side_effect=[False, True]),
             ConfigProxy=Mock(return_value=server_proxy_mock),
+            diff_list=Mock(return_value={}),
             do_state_change=Mock(return_value=Mock(errorcode=0))
         ):
             self.module = netscaler_server
@@ -203,6 +204,7 @@ class TestNetscalerServerModule(TestModule):
             get_nitro_client=m,
             server_exists=Mock(side_effect=[True, False]),
             ConfigProxy=Mock(return_value=server_proxy_mock),
+            diff_list=Mock(return_value={}),
             do_state_change=Mock(return_value=Mock(errorcode=0))
         ):
             self.module = netscaler_server
@@ -230,6 +232,7 @@ class TestNetscalerServerModule(TestModule):
             get_nitro_client=m,
             server_exists=Mock(side_effect=[False, True]),
             ConfigProxy=Mock(return_value=server_proxy_mock),
+            diff_list=Mock(return_value={}),
             do_state_change=Mock(return_value=Mock(errorcode=0))
         ):
             self.module = netscaler_server
@@ -284,12 +287,48 @@ class TestNetscalerServerModule(TestModule):
             get_nitro_client=m,
             server_exists=Mock(side_effect=[True, False]),
             ConfigProxy=Mock(return_value=server_proxy_mock),
+            diff_list=Mock(return_value={}),
             do_state_change=Mock(return_value=Mock(errorcode=1, message='Failed on purpose'))
         ):
             self.module = netscaler_server
             result = self.failed()
             self.assertEqual(result['msg'], 'Error when setting disabled state. errorcode: 1 message: Failed on purpose')
 
+    def test_disable_server_graceful(self):
+        set_module_args(dict(
+            nitro_user='user',
+            nitro_pass='pass',
+            nsip='1.1.1.1',
+            state='present',
+            disabled=True,
+            graceful=True
+        ))
+        from ansible.modules.network.netscaler import netscaler_server
+
+        client_mock = Mock()
+
+        m = Mock(return_value=client_mock)
+
+        server_proxy_mock = Mock()
+
+        d = {
+            'graceful': True,
+            'delay': 20,
+        }
+        with patch.multiple(
+            'ansible.modules.network.netscaler.netscaler_server',
+            nitro_exception=self.MockException,
+            get_nitro_client=m,
+            diff_list=Mock(return_value=d),
+            get_immutables_intersection=Mock(return_value=[]),
+            server_exists=Mock(side_effect=[True, True]),
+            ConfigProxy=Mock(return_value=server_proxy_mock),
+            do_state_change=Mock(return_value=Mock(errorcode=0))
+        ):
+            self.module = netscaler_server
+            result = self.exited()
+            self.assertEqual(d, {}, 'Graceful disable options were not discarded from the diff_list with the actual object')
+
     def test_new_server_execution_flow(self):
         set_module_args(dict(
             nitro_user='user',
diff --git a/test/units/modules/network/netscaler/test_netscaler_servicegroup.py b/test/units/modules/network/netscaler/test_netscaler_servicegroup.py
index 4f5c9f794ae..8c2d8a526b5 100644
--- a/test/units/modules/network/netscaler/test_netscaler_servicegroup.py
+++ b/test/units/modules/network/netscaler/test_netscaler_servicegroup.py
@@ -161,12 +161,15 @@ class TestNetscalerServicegroupModule(TestModule):
         m = MagicMock(return_value=servicegroup_proxy_mock)
         servicegroup_exists_mock = Mock(side_effect=[False, True])
 
+        servicegroup_servicegroupmember_binding_mock = Mock(count=Mock(return_value=0))
+
         with patch.multiple(
             'ansible.modules.network.netscaler.netscaler_servicegroup',
             ConfigProxy=m,
             servicegroup_exists=servicegroup_exists_mock,
             servicemembers_identical=Mock(side_effect=[False, True]),
             do_state_change=Mock(return_value=Mock(errorcode=0)),
+            servicegroup_servicegroupmember_binding=servicegroup_servicegroupmember_binding_mock,
             nitro_exception=self.MockException,
         ):
             self.module = netscaler_servicegroup