diff --git a/docs/en_US/images/preferences_misc_layout.png b/docs/en_US/images/preferences_misc_layout.png
new file mode 100644
index 0000000000000000000000000000000000000000..d04d3c85b07c9809cbabdc01f152c4273ab59139
GIT binary patch
diff --git a/docs/en_US/preferences.rst b/docs/en_US/preferences.rst
index 1f27961..241f24c 100644
--- a/docs/en_US/preferences.rst
+++ b/docs/en_US/preferences.rst
@@ -91,6 +91,11 @@ Expand the *Miscellaneous* node to specify miscellaneous display preferences.
 
 * Use the *User language* drop-down listbox to select the display language for the client.
 
+.. image:: images/preferences_misc_layout.png
+    :alt: Preferences dialog user layout section
+
+* When the *Lock layout?* switch is set to *True*, user will not be able to drag and drop panels.
+
 **The Paths Node**
 
 Expand the *Paths* node to specify the locations of supporting utility and help files.
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 724e677..e14be9a 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -845,6 +845,8 @@ def utils():
     # This will be opposite of use_space option
     editor_indent_with_tabs = False if editor_use_spaces else True
 
+    prefs = Preferences.module('miscellaneous')
+    panel_setting = prefs.preference('lock_panel_layout').get()
     # Try to fetch current libpq version from the driver
     try:
         from config import PG_DEFAULT_DRIVER
@@ -870,7 +872,8 @@ def utils():
             editor_insert_pair_brackets=insert_pair_brackets,
             editor_indent_with_tabs=editor_indent_with_tabs,
             app_name=config.APP_NAME,
-            pg_libpq_version=pg_libpq_version
+            pg_libpq_version=pg_libpq_version,
+            panel_setting=panel_setting
         ),
         200, {'Content-Type': 'application/x-javascript'})
 
diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js
index 46b6033..a75f49f 100644
--- a/web/pgadmin/browser/static/js/browser.js
+++ b/web/pgadmin/browser/static/js/browser.js
@@ -111,6 +111,7 @@ define('pgadmin.browser', [
         showTitle: true,
         isCloseable: false,
         isPrivate: true,
+        isFramePanel: true,
         icon: 'fa fa-binoculars',
         content: '<div id="tree" class="aciTree"></div>',
       }),
diff --git a/web/pgadmin/browser/static/js/panel.js b/web/pgadmin/browser/static/js/panel.js
index ab0681a..9a7dc7c 100644
--- a/web/pgadmin/browser/static/js/panel.js
+++ b/web/pgadmin/browser/static/js/panel.js
@@ -9,7 +9,7 @@ define(
       var defaults = [
         'name', 'title', 'width', 'height', 'showTitle', 'isCloseable',
         'isPrivate', 'content', 'icon', 'events', 'onCreate', 'elContainer',
-        'canHide', 'limit',
+        'canHide', 'limit', 'isMoveable', 'isFramePanel',
       ];
       _.extend(this, _.pick(options, defaults));
     };
@@ -22,6 +22,8 @@ define(
       showTitle: true,
       isCloseable: true,
       isPrivate: false,
+      isMoveable: pgBrowser.utils ? pgBrowser.utils.isPanelMoveable : true,
+      isFramePanel: false,
       content: '',
       icon: '',
       panel: null,
@@ -99,10 +101,33 @@ define(
                     myPanel.on(ev, that.handleVisibility.bind(myPanel, ev));
                   });
               }
+
+              if (!that.isFramePanel) {
+                pgBrowser.Events.on(
+                  'pgadmin-browser:preferences-updated',
+                  that.update_panel, myPanel
+                );
+                // If we set moveable directly then it doesn't take width properly
+                setTimeout(() => { myPanel.moveable(!!that.isMoveable); }, 10);
+              }
+
             },
           });
         }
       },
+
+      // We'll execute this function after preferences update
+      update_panel: function() {
+        let panel = this;
+        let preference = pgBrowser.get_preference(
+          'miscellaneous', 'lock_panel_layout'
+        );
+        if (preference && preference.value !== panel.moveable()) {
+          pgBrowser.utils.isPanelMoveable = preference.value;
+          panel.moveable(preference.value);
+        }
+      },
+
       eventFunc: function(eventName) {
         var name = $(this).data('pgAdminName');
 
diff --git a/web/pgadmin/browser/templates/browser/js/utils.js b/web/pgadmin/browser/templates/browser/js/utils.js
index be3b712..df57fa2 100644
--- a/web/pgadmin/browser/templates/browser/js/utils.js
+++ b/web/pgadmin/browser/templates/browser/js/utils.js
@@ -26,6 +26,7 @@ define('pgadmin.browser.utils',
     is_indent_with_tabs: '{{ editor_indent_with_tabs }}' == 'True',
     app_name: '{{ app_name }}',
     pg_libpq_version: {{pg_libpq_version|e}},
+    isPanelMoveable: '{{ panel_setting }}' == 'False',
 
     counter: {total: 0, loaded: 0},
     registerScripts: function (ctx) {
diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py
index 19e1828..050bc91 100644
--- a/web/pgadmin/misc/__init__.py
+++ b/web/pgadmin/misc/__init__.py
@@ -68,6 +68,11 @@ class MiscModule(PgAdminModule):
             category_label=gettext('User language'),
             options=lang_options
         )
+        self.misc_preference.register(
+            'layout', 'lock_panel_layout',
+            gettext("Lock layout?"), 'boolean', False,
+            category_label=gettext('Layout')
+        )
 
     def get_exposed_url_endpoints(self):
         """
diff --git a/web/pgadmin/preferences/static/js/preferences.js b/web/pgadmin/preferences/static/js/preferences.js
index 7014d62..769df7c 100644
--- a/web/pgadmin/preferences/static/js/preferences.js
+++ b/web/pgadmin/preferences/static/js/preferences.js
@@ -431,6 +431,9 @@ define('pgadmin.preferences', [
 
             if (e.button.text == gettext('OK')) {
               preferences.updateAll();
+              pgBrowser.Events.trigger(
+                'pgadmin-browser:preferences-updated', this, arguments
+              );
               // Refresh preferences cache
               setTimeout(pgBrowser.cache_preferences(), 2000);
             }
diff --git a/web/pgadmin/settings/__init__.py b/web/pgadmin/settings/__init__.py
index a2a84c6..de41212 100644
--- a/web/pgadmin/settings/__init__.py
+++ b/web/pgadmin/settings/__init__.py
@@ -115,7 +115,7 @@ def store(setting=None, value=None):
             store_setting(setting, value)
     except Exception as e:
         success = 0
-        errormsg = e.message
+        errormsg = str(e)
 
     try:
         info = traceback.format_exc()
diff --git a/web/pgadmin/static/css/webcabin.overrides.css b/web/pgadmin/static/css/webcabin.overrides.css
index 18d89f8..93a7f6b 100644
--- a/web/pgadmin/static/css/webcabin.overrides.css
+++ b/web/pgadmin/static/css/webcabin.overrides.css
@@ -399,3 +399,7 @@ i.wcTabIcon {
   background-size: 18px !important;
   height: 18px;
 }
+
+.wcTabScroller {
+  position: initial;
+}
diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js
index 473f20a..13df8c5 100644
--- a/web/pgadmin/tools/datagrid/static/js/datagrid.js
+++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js
@@ -525,6 +525,12 @@ define('pgadmin.datagrid', [
           // Set panel title and icon
           queryToolPanel.title('<span title="'+panel_title+'">'+panel_title+'</span>');
           queryToolPanel.icon('fa fa-bolt');
+          queryToolPanel.moveable(pgBrowser.utils.isPanelMoveable);
+          pgBrowser.Events.on(
+            'pgadmin-browser:preferences-updated',
+            pgAdmin.Browser.Panel.prototype.update_panel, queryToolPanel
+          );
+
           queryToolPanel.focus();
 
           // Listen on the panel closed event.
diff --git a/web/pgadmin/tools/debugger/static/js/debugger_ui.js b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
index f9049d8..0f8e55e 100644
--- a/web/pgadmin/tools/debugger/static/js/debugger_ui.js
+++ b/web/pgadmin/tools/debugger/static/js/debugger_ui.js
@@ -725,6 +725,11 @@ define([
                         );
 
                       panel.focus();
+                      panel.moveable(pgBrowser.utils.isPanelMoveable);
+                      pgBrowser.Events.on(
+                        'pgadmin-browser:preferences-updated',
+                        pgAdmin.Browser.Panel.prototype.update_panel, panel
+                      );
 
                       // Panel Closed event
                       panel.on(wcDocker.EVENT.CLOSED, function() {
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index 923ccea..ab96aac 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -176,6 +176,7 @@ define('tools.querytool', [
         height: '20%',
         isCloseable: false,
         isPrivate: true,
+        isMoveable: true,
       });
 
       sql_panel.load(main_docker);
diff --git a/web/regression/javascript/browser/panel_spec.js b/web/regression/javascript/browser/panel_spec.js
new file mode 100644
index 0000000..3f0184c
--- /dev/null
+++ b/web/regression/javascript/browser/panel_spec.js
@@ -0,0 +1,52 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2018, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+import pgAdmin from 'pgadmin';
+import Panel from 'browser/panel';
+
+describe('Panel', function () {
+  let pgBrowser = pgAdmin.Browser;
+  let Panel = pgAdmin.Browser.Panel;
+  let testPanel;
+  beforeEach(function () {
+    testPanel = new Panel({
+      name: 'test',
+      title: 'Test',
+      isMoveable: true,
+    });
+  });
+
+  describe('when we create a panel', function () {
+    describe('and it is moveable panel', function () {
+      it('it should call moveable method with true as argument', function () {
+        expect(testPanel.isMoveable).toBe(true);
+      });
+    });
+
+    describe('and it is non-moveable panel', function () {
+      beforeEach(function () {
+        testPanel.isMoveable = false;
+      });
+      it('it should call moveable method with false as argument', function () {
+        expect(testPanel.isMoveable).toBe(false);
+      });
+    });
+
+    describe('and user created panel without defining isMoveable then it should be moveable', function () {
+      beforeEach(function () {
+        testPanel = new Panel({
+          name: 'test',
+          title: 'Test',
+        });
+      });
+      it('it should call moveable method with true as argument', function () {
+        expect(testPanel.isMoveable).toBe(true);
+      });
+    });
+  });
+});
diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js
index 306a030..9932907 100644
--- a/web/webpack.test.config.js
+++ b/web/webpack.test.config.js
@@ -80,6 +80,7 @@ module.exports = {
       'pgadmin.alertifyjs': sourcesDir + '/js/alertify.pgadmin.defaults',
       'pgadmin.backgrid': sourcesDir + '/js/backgrid.pgadmin',
       'pgadmin.backform': sourcesDir + '/js/backform.pgadmin',
+      'wcdocker': path.join(__dirname, './node_modules/webcabin-docker/Build/wcDocker'),
     },
   },
 };
