diff --git a/web/pgadmin/tools/maintenance/__init__.py b/web/pgadmin/tools/maintenance/__init__.py
new file mode 100644
index 0000000..02e4c1b
--- /dev/null
+++ b/web/pgadmin/tools/maintenance/__init__.py
@@ -0,0 +1,193 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the maintenance tool for vacuum"""
+
+MODULE_NAME = 'maintenance'
+
+import json
+from random import randint
+from flask import url_for, Response, render_template, request, make_response, jsonify, current_app
+from pgadmin.utils import PgAdminModule
+from pgadmin.utils.ajax import bad_request
+from flask.ext.babel import gettext
+from flask.ext.security import login_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.model import db, Jobs, Server
+from pgadmin.utils.preferences import Preferences
+
+class MaintenanceModule(PgAdminModule):
+    """
+    class MaintenanceModule(PgAdminModule)
+
+        A module class for maintenance tools of vacuum which is derived from PgAdminModule.
+
+    Methods:
+    -------
+    * get_own_javascripts(self)
+      - Method is used to load the required javascript files for miantenance tool module
+
+    * get_pg_utility_dir_preference(self)
+      - Method is used to get the PG utilities path set in preferences.
+
+    * get_edb_utility_dir_preference(self)
+      - Method is used to get the EDB utilities path set in preferences.
+
+    * register_preferences(self)
+      - Register the storage dir, PG and EDB utilities preferences.
+
+    """
+    LABEL = gettext('Utilities')
+
+    def get_own_javascripts(self):
+        scripts = list()
+        for name, script in [
+                ['pgadmin.tools.maintenance', 'js/maintenance']
+                ]:
+            scripts.append({
+                'name': name,
+                'path': url_for('maintenance.index') + script,
+                'when': None
+                })
+
+        return scripts
+
+    def get_pg_utility_dir_preference(self):
+        return self.pg_utility_dir
+
+    def get_edb_utility_dir_preference(self):
+        return self.edb_utility_dir
+
+    def register_preferences(self):
+        # Register 'PG specific utility binary directory' preference
+        self.pg_utility_dir = self.preference.register(
+            'options', 'pg_utilities_bin_dir',
+            gettext("PG bin path"), 'text', '/',
+            category_label=gettext('BIN path')
+        )
+
+        # Register 'EDB specific utility binary directory' preference
+        self.edb_utility_dir = self.preference.register(
+            'options', 'edb_utilities_bin_dir',
+            gettext("EDB bin path"), 'text', '/',
+            category_label=gettext('BIN path')
+        )
+
+
+blueprint = MaintenanceModule(MODULE_NAME, __name__)
+
+@blueprint.route("/")
+@login_required
+def index():
+    return bad_request(errormsg=gettext("This URL can not be called directly!"))
+
+
+@blueprint.route("/js/maintenance.js")
+@login_required
+def script():
+    """render the maintenance tool of vacuum javascript file"""
+    return Response(response=render_template("maintenance/js/maintenance.js", _=gettext),
+                    status=200,
+                    mimetype="application/javascript")
+
+
+@blueprint.route('/create_job/<int:sid>/<int:did>', methods=['POST'])
+@login_required
+def create_maintenance_job(sid, did):
+    """
+    Args:
+        sid: Server ID
+        did: Database ID
+
+        Creates a new job for maintenance vacuum operation
+
+    Returns:
+        None
+    """
+    if request.form:
+        # Convert ImmutableDict to dict
+        data = dict(request.form)
+        data = json.loads(data['data'][0])
+    else:
+        data = json.loads(request.data.decode())
+
+    # Fetch the server details like hostname, port, roles etc
+    server = Server.query.filter_by(
+        id=sid).first()
+
+    if server is None:
+        return make_json_response(
+            success=0,
+            errormsg=gettext("Couldn't find the given server")
+        )
+
+    # To fetch MetaData for the server
+    manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(server.id)
+    conn = manager.connection()
+    connected = conn.connected()
+
+    if not connected:
+        return make_json_response(
+            success=0,
+            errormsg=gettext("Please connect to the server first...")
+        )
+
+    # Set psql binary path from preference
+    if manager.server_type == 'ppas':
+        # EDB specific backup tool
+        pgsql_utility_dir = blueprint.get_edb_utility_dir_preference().get()
+    else:
+        pgsql_utility_dir = blueprint.get_pg_utility_dir_preference().get()
+
+    pgsql_utility_dir += 'psql'
+
+    # Create the command for the vacuum operation
+    arguments = render_template(
+        'maintenance/sql/command.sql',
+        conn = conn,
+        data=data
+    )
+
+    # Create complete command and arguments string
+    command_string = render_template(
+        'maintenance/sql/arguments.sql',
+        conn = conn,
+        server=server,
+        data=data,
+        args=arguments
+    )
+
+
+    try:
+        # Generate random job id
+        jid = randint(1001, 9999)
+        create_job = Jobs(
+            job_id=jid,
+            command=pgsql_utility_dir,
+            arguments=command_string
+        )
+        # Create job execution string and save to database
+        db.session.add(create_job)
+        db.session.commit()
+
+    except Exception as e:
+        current_app.logger.exception(e)
+        return make_json_response(
+            status=410,
+            success=0,
+            errormsg=str(e)
+        )
+
+    # Return response
+    return make_json_response(
+        data={'job_id': jid, 'status': True, 'info': 'Maintenance job created'}
+    )
\ No newline at end of file
diff --git a/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js b/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js
new file mode 100644
index 0000000..f494a9e
--- /dev/null
+++ b/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js
@@ -0,0 +1,288 @@
+define(
+  ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin',
+  'pgadmin.browser', 'backbone', 'backgrid', 'backform',
+  'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui'],
+  function($, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid, Backform) {
+
+  pgAdmin = pgAdmin || window.pgAdmin || {};
+
+  var pgTools = pgAdmin.Tools = pgAdmin.Tools || {};
+
+  // Return back, this has been called more than once
+  if (pgAdmin.Tools.maintenance)
+    return pgAdmin.Tools.maintenance;
+
+  var CustomSwitchControl = Backform.CustomSwitchControl = Backform.SwitchControl.extend({
+      template: _.template([
+        '<label class="<%=Backform.controlLabelClassName%> custom_switch_label_class"><%=label%></label>',
+        '<div class="<%=Backform.controlsClassName%> custom_switch_control_class">',
+        '  <div class="checkbox">',
+        '    <label>',
+        '      <input type="checkbox" class="<%=extraClasses.join(\' \')%>" name="<%=name%>" <%=value ? "checked=\'checked\'" : ""%> <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> />',
+        '    </label>',
+        '  </div>',
+        '</div>',
+        '<% if (helpMessage && helpMessage.length) { %>',
+        '  <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
+        '<% } %>'
+      ].join("\n")),
+      className: 'pgadmin-control-group form-group col-xs-6'
+    });
+
+  // Main model for Maintenance functionality
+  var MaintenanceModel = Backbone.Model.extend({
+    defaults: {
+      main_operation: 'VACUUM',
+      vacuum_option_full: false,
+      vacuum_option_freeze: false,
+      vacuum_option_analyze: false,
+      verbose_message: true
+    },
+    schema: [
+      {
+        id: 'main_operation', label:'{{ _('Maintenance operation') }}', cell: 'string',
+        type: 'text', control: 'node-ajax-options', group: '{{ _('Options') }}',
+        options:[
+          {'label': "VACUUM", 'value': "VACUUM"},
+          {'label': "ANALYZE", 'value': "ANALYZE"},
+          {'label': "REINDEX", 'value': "REINDEX"},
+          {'label': "CLUSTER", 'value': "CLUSTER"},
+        ],
+        select2: {
+          allowClear: false,
+          width: "100%",
+          placeholder: '{{ _('Select from list...') }}'
+        },
+      },
+      {
+        type: 'nested', control: 'fieldset', label:'{{ _('Vacuum') }}', group: '{{ _('Options') }}',
+        schema:[{
+          id: 'vacuum_option_full', disabled: false, group: '{{ _('Vacuum') }}', disabled: 'isDisabled',
+          control: Backform.CustomSwitchControl, label: '{{ _('FULL') }}', deps: ['main_operation']
+        },{
+          id: 'vacuum_option_freeze', disabled: false, deps: ['main_operation'], disabled: 'isDisabled',
+          control: Backform.CustomSwitchControl, label: '{{ _('FREEZE') }}', group: '{{ _('Vacuum') }}'
+        },{
+          id: 'vacuum_option_analyze', disabled: false, deps: ['main_operation'], disabled: 'isDisabled',
+          control: Backform.CustomSwitchControl, label: '{{ _('ALALYZE') }}', group: '{{ _('Vacuum') }}'
+        }]
+      },
+      {
+        id: 'verbose_message', disabled: false, group: '{{ _('Options') }}', deps: ['main_operation'],
+        control: Backform.CustomSwitchControl, label: '{{ _('Verbose Messages') }}', disabled: 'isDisabled'
+      }
+    ],
+
+    // Enable/Disable the items based on the user maintenance operation selection
+    isDisabled: function(m) {
+      name = this.name;
+      switch(name) {
+        case 'vacuum_option_full':
+        case 'vacuum_option_freeze':
+        case 'vacuum_option_analyze':
+          if (m.get('main_operation') != 'VACUUM') {
+            return true;
+          }
+          else {
+            return false;
+          }
+          break;
+        case 'verbose_message':
+          if (m.get('main_operation') == 'REINDEX') {
+            return true;
+          }
+          else {
+            return false;
+          }
+          break;
+        default:
+          return false;
+      }
+      return false;
+    },
+  });
+
+  pgTools.maintenance = {
+      init: function() {
+
+        // We do not want to initialize the module multiple times.
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        var maintenance_supported_nodes = [
+              'database', 'table'
+            ];
+
+        /**
+         Enable/disable Maintenance menu in tools based on node selected.
+         Maintenance menu will be enabled only when user select table and database node.
+        */
+        menu_enabled = function(itemData, item, data) {
+         var t = pgBrowser.tree, i = item, d = itemData;
+         var parent_item = t.hasParent(i) ? t.parent(i): null,
+             parent_data = parent_item ? t.itemData(parent_item) : null;
+           if(!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data))
+             return (
+               (_.indexOf(maintenance_supported_nodes, d._type) !== -1 &&
+               parent_data._type != 'catalog') ? true: false
+             );
+           else
+             return false;
+        };
+
+        var menus = [{
+          name: 'maintenance', module: this,
+          applies: ['tools'], callback: 'callback_maintenace',
+          priority: 10, label: '{{ _('Maintenance...') }}',
+          icon: 'fa fa-wrench', enable: menu_enabled
+        }];
+
+        // Add supported menus into the menus list
+        for (var idx = 0; idx < maintenance_supported_nodes.length; idx++) {
+          menus.push({
+            name: 'maintenance_context_' + maintenance_supported_nodes[idx],
+            node: maintenance_supported_nodes[idx], module: this,
+            applies: ['context'], callback: 'callback_maintenace',
+            priority: 10, label: '{{_("Maintenance...") }}',
+            icon: 'fa fa-wrench', enable: menu_enabled
+          });
+        }
+        pgBrowser.add_menus(menus);
+      },
+
+      /*
+        Open the dialog for the maintenance functionality
+      */
+      callback_maintenace: function(args, item) {
+        var self = this;
+        var input = args || {},
+          t = pgBrowser.tree,
+          i = item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined,
+          node = d && pgBrowser.Nodes[d._type];
+
+        if (!d)
+          return;
+
+        var objName = d.label;
+        var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
+
+        if (!Alertify.MaintenanceDialog) {
+          Alertify.dialog('MaintenanceDialog', function factory() {
+
+            return {
+              main:function(title) {
+                this.set('title', title);
+              },
+              setup:function() {
+                return {
+                  buttons:[{ text: "{{ _('OK') }}", key: 27, className: "btn btn-primary fa fa-lg fa-save pg-alertify-button" },
+                       { text: "{{ _('Cancel') }}", key: 27, className: "btn btn-danger fa fa-lg fa-times pg-alertify-button" }],
+                  options: { modal: 0}
+                };
+              },
+              // Callback functions when click on the buttons of the Alertify dialogs
+              callback: function(e) {
+                if (e.button.text === "{{ _('OK') }}") {
+
+                  var schema = '';
+                  var table = '';
+                  var i = pgBrowser.tree.selected(),
+                  d = i && i.length == 1 ? pgBrowser.tree.itemData(i) : undefined,
+                  node = d && pgBrowser.Nodes[d._type];
+
+                  if (!d)
+                    return;
+
+                  var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
+
+                  if (treeInfo.schema != undefined) {
+                    schema = treeInfo.schema.label;
+                  }
+                  if (treeInfo.table != undefined) {
+                    table = treeInfo.table.label;
+                  }
+
+                  this.view.model.set({'database': treeInfo.database.label,
+                                      'schema': schema,
+                                      'table': table})
+
+                    baseUrl = "{{ url_for('maintenance.index') }}" +
+                    "create_job/" + treeInfo.server._id + "/" + treeInfo.database._id,
+                    args =  this.view.model.toJSON();
+
+                  $.ajax({
+                    url: baseUrl,
+                    method: 'POST',
+                    data:{ 'data': JSON.stringify(args) },
+                    success: function(res) {
+                      if (res.data.status) {
+                        //Do nothing as we are creating the job and exiting from the main dialog
+                        Alertify.success(res.data.info);
+                      }
+                      else {
+                        Alertify.error(res.data.info);
+                      }
+                    },
+                    error: function(e) {
+                      Alertify.alert(
+                        "{{ _('Maintenance job creation failed') }}"
+                      );
+                    }
+                  });
+                }
+              },
+              build:function() {
+
+              },
+              hooks: {
+                onclose: function() {
+                  if (this.view) {
+                    this.view.remove({data: true, internal: true, silent: true});
+                  }
+                }
+              },
+              prepare:function() {
+                // Main maintenance tool dialog container
+                var $container = $("<div class='maintenance_dlg'></div>");
+
+                var t = pgBrowser.tree,
+                  i = t.selected(),
+                  d = i && i.length == 1 ? t.itemData(i) : undefined,
+                  node = d && pgBrowser.Nodes[d._type];
+
+                if (!d)
+                  return;
+
+                var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
+
+                var newModel = new MaintenanceModel (
+                  {}, {node_info: treeInfo}
+                  ),
+                  fields = Backform.generateViewSchema(
+                    treeInfo, newModel, 'create', node, treeInfo.server, true
+                  );
+
+                  var view = this.view = new Backform.Dialog({
+                    el: $container, model: newModel, schema: fields
+                  });
+
+                  $(this.elements.body.childNodes[0]).addClass('alertify_tools_dialog_properties obj_properties');
+
+                  view.render();
+
+                  this.elements.content.appendChild($container.get(0));
+              }
+            };
+          });
+        }
+
+        // Open the Alertify dialog
+        Alertify.MaintenanceDialog('Maintenance...').set('resizable',true).resizeTo('60%','80%');
+      },
+    };
+
+    return pgAdmin.Tools.maintenance;
+  });
diff --git a/web/pgadmin/tools/maintenance/templates/maintenance/sql/arguments.sql b/web/pgadmin/tools/maintenance/templates/maintenance/sql/arguments.sql
new file mode 100644
index 0000000..060808c
--- /dev/null
+++ b/web/pgadmin/tools/maintenance/templates/maintenance/sql/arguments.sql
@@ -0,0 +1 @@
+-h {{ conn|qtIdent(server.host) }} -p {{ server.port }} -U {{ conn|qtIdent(server.username) }} {{ conn|qtIdent(data.database) }} -c "{{ args }}"
\ No newline at end of file
diff --git a/web/pgadmin/tools/maintenance/templates/maintenance/sql/command.sql b/web/pgadmin/tools/maintenance/templates/maintenance/sql/command.sql
new file mode 100644
index 0000000..24fad82
--- /dev/null
+++ b/web/pgadmin/tools/maintenance/templates/maintenance/sql/command.sql
@@ -0,0 +1,12 @@
+{% if data.main_operation == "VACUUM" %}
+VACUUM{% if data.vacuum_option_full %} FULL{% endif %}{% if data.vacuum_option_freeze %} FREEZE{% endif %}{% if data.vacuum_option_analyze %} ANALYZE{% endif %}{% if data.verbose_message %} VERBOSE{% endif %}{% if data.schema != '' %} {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %}
+{% endif %}
+{% if data.main_operation == "ANALYZE" %}
+ANALYZE{% if data.verbose_message %} VERBOSE{% endif %}{% if data.schema != '' %} {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %}
+{% endif %}
+{% if data.main_operation == "REINDEX" %}
+REINDEX{% if data.schema == '' %} DATABASE {{ conn|qtIdent(data.database) }}{% else %} TABLE {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %}
+{% endif %}
+{% if data.main_operation == "CLUSTER" %}
+CLUSTER{% if data.verbose_message %} VERBOSE {% endif %}{% if data.schema != '' %} {{ conn|qtIdent(data.schema) }}.{{ conn|qtIdent(data.table) }}{% endif %}
+{% endif %}
\ No newline at end of file
