diff --git a/docs/en_US/build_code_snippet.py b/docs/en_US/build_code_snippet.py
index 874e3f764..9bfbd528a 100644
--- a/docs/en_US/build_code_snippet.py
+++ b/docs/en_US/build_code_snippet.py
@@ -1,11 +1,7 @@
 import os
 import sys
 import inspect
-
-if sys.version_info[0] >= 3:
-    import builtins
-else:
-    import __builtin__ as builtins
+import builtins
 
 # Ensure the global server mode is set.
 builtins.SERVER_MODE = None
diff --git a/docs/en_US/conf.py b/docs/en_US/conf.py
index 2694d78ed..865c04f49 100644
--- a/docs/en_US/conf.py
+++ b/docs/en_US/conf.py
@@ -14,11 +14,7 @@
 
 import os
 import sys
-
-if sys.version_info[0] >= 3:
-    import builtins
-else:
-    import __builtin__ as builtins
+import builtins
 
 # Ensure the global server mode is set.
 builtins.SERVER_MODE = None
diff --git a/pkg/pip/setup_pip.py b/pkg/pip/setup_pip.py
index fc797d52f..8e0dc6eaa 100644
--- a/pkg/pip/setup_pip.py
+++ b/pkg/pip/setup_pip.py
@@ -9,15 +9,11 @@
 
 import os
 import sys
+import builtins
 
 from setuptools import setup
 from codecs import open
 
-if sys.version_info[0] >= 3:
-    import builtins
-else:
-    import __builtin__ as builtins
-
 # Ensure the global server mode is set.
 builtins.SERVER_MODE = None
 
diff --git a/pkg/win32/README.txt b/pkg/win32/README.txt
index fea1e5655..d82b89e74 100644
--- a/pkg/win32/README.txt
+++ b/pkg/win32/README.txt
@@ -4,7 +4,7 @@
 To generate a pgAdmin 4 installer for Windows bit, the following packages must be installed:
 
 1. Python installation
-  - Python 2.7 or 3.4+ or above from https://www.python.org/
+  - Python 3.4+ or above from https://www.python.org/
 
 2. QT installation
   - Qt 4.6 through 5.5 from http://www.qt.io/
@@ -21,8 +21,8 @@ Building: Depending upon the archicture of the OS(x86|amd64) set then environmen
 
 1. Set the PYTHON environment variable to the Python root installation directory, e.g. for x86
 
-   SET "PYTHON_HOME=C:\Python27"
-   SET "PYTHON_DLL=C:\Windows\System32\python27.dll"
+   SET "PYTHON_HOME=C:\Python38"
+   SET "PYTHON_DLL=C:\Windows\System32\python38.dll"
 
 2. Set the QTDIR environment variable to the QT root installation directory, e.g. for x86
 
diff --git a/tools/dependency_inventory.py b/tools/dependency_inventory.py
index ef6938910..77a3ed7a8 100644
--- a/tools/dependency_inventory.py
+++ b/tools/dependency_inventory.py
@@ -52,10 +52,7 @@ def get_python_deps():
                                 "/../requirements.txt")
 
     with open(req_file, 'r') as req_file_p:
-        if sys.version_info[0] >= 3:
-            required = req_file_p.read().splitlines()
-        else:
-            required = req_file_p.read().decode("utf-8").splitlines()
+        required = req_file_p.read().splitlines()
 
     # Get the package info from the requirements file
     requirements = pkg_resources.parse_requirements(required)
diff --git a/web/pgAdmin4.wsgi b/web/pgAdmin4.wsgi
index cf3ad0c21..77af5c6ec 100644
--- a/web/pgAdmin4.wsgi
+++ b/web/pgAdmin4.wsgi
@@ -9,16 +9,12 @@
 
 import os
 import sys
+import builtins
 
 root = os.path.dirname(os.path.realpath(__file__))
 if sys.path[0] != root:
     sys.path.insert(0, root)
 
-if sys.version_info[0] >= 3:
-    import builtins
-else:
-    import __builtin__ as builtins
-
 # Ensure the global server mode is set.
 builtins.SERVER_MODE = True
 
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index ae4a0d3f4..32bf3358b 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -43,12 +43,9 @@ from pgadmin import authenticate
 # If script is running under python3, it will not have the xrange function
 # defined
 winreg = None
-if sys.version_info[0] >= 3:
-    xrange = range
-    if os.name == 'nt':
-        import winreg
-elif os.name == 'nt':
-    import _winreg as winreg
+xrange = range
+if os.name == 'nt':
+    import winreg
 
 
 class PgAdmin(Flask):
diff --git a/web/pgadmin/misc/bgprocess/process_executor.py b/web/pgadmin/misc/bgprocess/process_executor.py
index 5e9b4d048..053cf566b 100755
--- a/web/pgadmin/misc/bgprocess/process_executor.py
+++ b/web/pgadmin/misc/bgprocess/process_executor.py
@@ -40,7 +40,6 @@ from threading import Thread
 import signal
 
 _IS_WIN = (os.name == 'nt')
-_IS_PY2 = (sys.version_info[0] == 2)
 _ZERO = timedelta(0)
 _sys_encoding = None
 _fs_encoding = None
@@ -48,16 +47,12 @@ _u = None
 _out_dir = None
 _log_file = None
 
-if _IS_PY2:
-    def _log(msg):
-        with open(_log_file, 'a') as fp:
-            fp.write(('INFO:: %s\n' % str(msg)))
-else:
-    def _log(msg):
-        with open(_log_file, 'a') as fp:
-            fp.write(
-                ('INFO:: %s\n' % msg.encode('ascii', 'xmlcharrefreplace'))
-            )
+
+def _log(msg):
+    with open(_log_file, 'a') as fp:
+        fp.write(
+            ('INFO:: %s\n' % msg.encode('ascii', 'xmlcharrefreplace'))
+        )
 
 
 def unescape_dquotes_process_arg(arg):
@@ -193,61 +188,32 @@ class ProcessLogger(Thread):
         self.process = process
         self.stream = stream
 
-    if not _IS_PY2:
-        def log(self, msg):
-            """
-            This function will update log file
-
-            Args:
-                msg: message
-
-            Returns:
-                None
-            """
-            # Write into log file
-            if self.logger:
-                if msg:
-                    self.logger.write(
-                        get_current_time(
-                            format='%y%m%d%H%M%S%f'
-                        ).encode('utf-8')
-                    )
-                    self.logger.write(b',')
-                    self.logger.write(
-                        msg.lstrip(b'\r\n' if _IS_WIN else b'\n')
-                    )
-                    self.logger.write(os.linesep.encode('utf-8'))
+    def log(self, msg):
+        """
+        This function will update log file
 
-                return True
-            return False
-    else:
-        def log(self, msg):
-            """
-            This function will update log file
-
-            Args:
-                msg: message
-
-            Returns:
-                None
-            """
-            # Write into log file
-            if self.logger:
-                if msg:
-                    self.logger.write(
-                        b'{0},{1}{2}'.format(
-                            get_current_time(
-                                format='%y%m%d%H%M%S%f'
-                            ),
-                            msg.lstrip(
-                                b'\r\n' if _IS_WIN else b'\n'
-                            ),
-                            os.linesep
-                        )
-                    )
+        Args:
+            msg: message
 
-                return True
-            return False
+        Returns:
+            None
+        """
+        # Write into log file
+        if self.logger:
+            if msg:
+                self.logger.write(
+                    get_current_time(
+                        format='%y%m%d%H%M%S%f'
+                    ).encode('utf-8')
+                )
+                self.logger.write(b',')
+                self.logger.write(
+                    msg.lstrip(b'\r\n' if _IS_WIN else b'\n')
+                )
+                self.logger.write(os.linesep.encode('utf-8'))
+
+            return True
+        return False
 
     def run(self):
         if self.process and self.stream:
@@ -327,11 +293,7 @@ def execute(argv):
         kwargs['shell'] = True if _IS_WIN else False
 
         # We need environment variables & values in string
-        if _IS_PY2:
-            _log('Converting the environment variable in the bytes format...')
-            kwargs['env'] = convert_environment_variables(os.environ.copy())
-        else:
-            kwargs['env'] = os.environ.copy()
+        kwargs['env'] = os.environ.copy()
 
         _log('Starting the command execution...')
         process = Popen(
@@ -454,9 +416,6 @@ if __name__ == '__main__':
         _fs_encoding = 'utf-8'
 
     def u(_s, _encoding=_sys_encoding):
-        if _IS_PY2:
-            if isinstance(_s, str):
-                return unicode(_s, _encoding)
         return _s
     _u = u
 
diff --git a/web/pgadmin/misc/bgprocess/processes.py b/web/pgadmin/misc/bgprocess/processes.py
index 6231cce2a..820b68f20 100644
--- a/web/pgadmin/misc/bgprocess/processes.py
+++ b/web/pgadmin/misc/bgprocess/processes.py
@@ -183,15 +183,7 @@ class BatchProcess(object):
         csv_writer = csv.writer(
             args_csv_io, delimiter=str(','), quoting=csv.QUOTE_MINIMAL
         )
-        if sys.version_info[0] == 2:
-            csv_writer.writerow(
-                [
-                    a.encode('utf-8')
-                    if isinstance(a, unicode) else a for a in _args
-                ]
-            )
-        else:
-            csv_writer.writerow(_args)
+        csv_writer.writerow(_args)
 
         args_val = args_csv_io.getvalue().strip(str('\r\n'))
         tmp_desc = dumps(self.desc)
diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py
index 39aa39315..dddeff39b 100644
--- a/web/pgadmin/misc/file_manager/__init__.py
+++ b/web/pgadmin/misc/file_manager/__init__.py
@@ -98,9 +98,7 @@ def splitext(path):
 def is_folder_hidden(filepath):
     if _platform == "win32":
         try:
-            attrs = ctypes.windll.kernel32.GetFileAttributesW(
-                unicode(filepath) if sys.version_info[0] < 3 else filepath
-            )
+            attrs = ctypes.windll.kernel32.GetFileAttributesW(filepath)
             assert attrs != -1
             result = bool(attrs & 2)
         except (AttributeError, AssertionError):
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index 658f091a1..3e98ed3f6 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -52,11 +52,6 @@ try:
 except ImportError:
     from urllib.parse import unquote
 
-if sys.version_info[0:2] <= (2, 7):
-    IS_PY2 = True
-else:
-    IS_PY2 = False
-
 
 class SqlEditorModule(PgAdminModule):
     """
@@ -321,8 +316,7 @@ def extract_sql_from_network_parameters(request_data, request_arguments,
     if request_data:
         sql_parameters = json.loads(request_data, encoding='utf-8')
 
-        if (IS_PY2 and type(sql_parameters) is unicode) \
-                or type(sql_parameters) is str:
+        if type(sql_parameters) is str:
             return dict(sql=str(sql_parameters), explain_plan=None)
         return sql_parameters
     else:
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index 828bd19d7..ab978aa9f 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -158,7 +158,6 @@ class PgAdminModule(Blueprint):
         return res
 
 
-IS_PY2 = (sys.version_info[0] == 2)
 IS_WIN = (os.name == 'nt')
 
 sys_encoding = sys.getdefaultencoding()
@@ -175,16 +174,10 @@ if not fs_encoding or fs_encoding == 'ascii':
 
 
 def u(_s, _encoding=sys_encoding):
-    if IS_PY2:
-        if isinstance(_s, str):
-            return unicode(_s, _encoding)
     return _s
 
 
 def file_quote(_p):
-    if IS_PY2:
-        if isinstance(_p, unicode):
-            return _p.encode(fs_encoding)
     return _p
 
 
@@ -192,25 +185,10 @@ if IS_WIN:
     import ctypes
     from ctypes import wintypes
 
-    if IS_PY2:
-        def env(name):
-            if IS_PY2:
-                # Make sure string argument is unicode
-                name = unicode(name)
-            n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
-
-            if n == 0:
-                return None
-
-            buf = ctypes.create_unicode_buffer(u'\0' * n)
-            ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
-
-            return buf.value
-    else:
-        def env(name):
-            if name in os.environ:
-                return os.environ[name]
-            return None
+    def env(name):
+        if name in os.environ:
+            return os.environ[name]
+        return None
 
     _GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW
     _GetShortPathNameW.argtypes = [
diff --git a/web/pgadmin/utils/csv.py b/web/pgadmin/utils/csv.py
index 991e06657..89615d449 100644
--- a/web/pgadmin/utils/csv.py
+++ b/web/pgadmin/utils/csv.py
@@ -75,17 +75,10 @@ from csv import (
 )
 
 # Stuff needed from six
-import sys
-PY3 = sys.version_info[0] == 3
-if PY3:
-    string_types = str
-    text_type = str
-    binary_type = bytes
-    unichr = chr
-else:
-    string_types = basestring
-    text_type = unicode
-    binary_type = str
+string_types = str
+text_type = str
+binary_type = bytes
+unichr = chr
 
 
 class QuoteStrategy(object):
diff --git a/web/pgadmin/utils/driver/psycopg2/connection.py b/web/pgadmin/utils/driver/psycopg2/connection.py
index 21799c9c0..6effd510e 100644
--- a/web/pgadmin/utils/driver/psycopg2/connection.py
+++ b/web/pgadmin/utils/driver/psycopg2/connection.py
@@ -15,7 +15,6 @@ object.
 
 import random
 import select
-import sys
 import six
 import datetime
 from collections import deque
@@ -39,13 +38,7 @@ from .typecast import register_global_typecasters, \
 from .encoding import getEncoding, configureDriverEncodings
 from pgadmin.utils import csv
 from pgadmin.utils.master_password import get_crypt_key
-
-if sys.version_info < (3,):
-    from StringIO import StringIO
-    IS_PY2 = True
-else:
-    from io import StringIO
-    IS_PY2 = False
+from io import StringIO
 
 _ = gettext
 
@@ -692,8 +685,7 @@ WHERE
             u"{conn_id} (Query-id: {query_id}):\n{query}".format(
                 server_id=self.manager.sid,
                 conn_id=self.conn_id,
-                query=query.decode(self.python_encoding) if
-                sys.version_info < (3,) else query,
+                query=query,
                 query_id=query_id
             )
         )
@@ -721,33 +713,6 @@ WHERE
             return False, \
                 gettext('The query executed did not return any data.')
 
-        def handle_json_data(json_columns, results):
-            """
-            [ This is only for Python2.x]
-            This function will be useful to handle json data types.
-            We will dump json data as proper json instead of unicode values
-
-            Args:
-                json_columns: Columns which contains json data
-                results: Query result
-
-            Returns:
-                results
-            """
-            # Only if Python2 and there are columns with JSON type
-            if IS_PY2 and len(json_columns) > 0:
-                temp_results = []
-                for row in results:
-                    res = dict()
-                    for k, v in row.items():
-                        if k in json_columns:
-                            res[k] = json.dumps(v)
-                        else:
-                            res[k] = v
-                    temp_results.append(res)
-                results = temp_results
-            return results
-
         def convert_keys_to_unicode(results, conn_encoding):
             """
             [ This is only for Python2.x]
@@ -809,15 +774,10 @@ WHERE
             for c in cur.ordered_description():
                 # This is to handle the case in which column name is non-ascii
                 column_name = c.to_dict()['name']
-                if IS_PY2:
-                    column_name = column_name.decode(conn_encoding)
                 header.append(column_name)
                 if c.to_dict()['type_code'] in ALL_JSON_TYPES:
                     json_columns.append(column_name)
 
-            if IS_PY2:
-                results = convert_keys_to_unicode(results, conn_encoding)
-
             res_io = StringIO()
 
             if quote == 'strings':
@@ -848,7 +808,6 @@ WHERE
             )
 
             csv_writer.writeheader()
-            results = handle_json_data(json_columns, results)
             # Replace the null values with given string if configured.
             if replace_nulls_with is not None:
                 results = handle_null_values(results, replace_nulls_with)
@@ -872,10 +831,6 @@ WHERE
                     replace_nulls_with=replace_nulls_with
                 )
 
-                if IS_PY2:
-                    results = convert_keys_to_unicode(results, conn_encoding)
-
-                results = handle_json_data(json_columns, results)
                 # Replace the null values with given string if configured.
                 if replace_nulls_with is not None:
                     results = handle_null_values(results, replace_nulls_with)
diff --git a/web/pgadmin/utils/driver/psycopg2/typecast.py b/web/pgadmin/utils/driver/psycopg2/typecast.py
index 05ea07279..5b8810e24 100644
--- a/web/pgadmin/utils/driver/psycopg2/typecast.py
+++ b/web/pgadmin/utils/driver/psycopg2/typecast.py
@@ -12,8 +12,6 @@ Typecast various data types so that they can be compatible with Javascript
 data types.
 """
 
-import sys
-
 from psycopg2 import STRING as _STRING
 import psycopg2
 from psycopg2.extensions import encodings
@@ -124,10 +122,6 @@ PSYCOPG_SUPPORTED_RANGE_ARRAY_TYPES = (3905, 3927, 3907, 3913, 3909, 3911)
 
 
 def register_global_typecasters():
-    if sys.version_info < (3,):
-        psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
-        psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)
-
     unicode_type_for_record = psycopg2.extensions.new_type(
         (2249,),
         "RECORD",
@@ -186,19 +180,12 @@ def register_string_typecasters(connection):
     postgres_encoding, python_encoding, typecast_encoding = \
         getEncoding(connection.encoding)
     if postgres_encoding != 'UNICODE':
-        if sys.version_info >= (3,):
-            def non_ascii_escape(value, cursor):
-                if value is None:
-                    return None
-                return bytes(
-                    value, encodings[cursor.connection.encoding]
-                ).decode(typecast_encoding, errors='replace')
-        else:
-            def non_ascii_escape(value, cursor):
-                if value is None:
-                    return None
-                return value.decode(typecast_encoding, errors='replace')
-                # return value
+        def non_ascii_escape(value, cursor):
+            if value is None:
+                return None
+            return bytes(
+                value, encodings[cursor.connection.encoding]
+            ).decode(typecast_encoding, errors='replace')
 
         unicode_type = psycopg2.extensions.new_type(
             # "char", name, text, character, character varying
diff --git a/web/pgadmin/utils/sqlautocomplete/sqlcompletion.py b/web/pgadmin/utils/sqlautocomplete/sqlcompletion.py
index 41641f439..c38c04a6e 100644
--- a/web/pgadmin/utils/sqlautocomplete/sqlcompletion.py
+++ b/web/pgadmin/utils/sqlautocomplete/sqlcompletion.py
@@ -9,13 +9,7 @@ from .parseutils.utils import (
 from .parseutils.tables import extract_tables
 from .parseutils.ctes import isolate_query_ctes
 
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-
-if PY3:
-    string_types = str
-else:
-    string_types = basestring
+string_types = str
 
 
 Special = namedtuple('Special', [])
diff --git a/web/setup.py b/web/setup.py
index eb7d90445..6bb8527a6 100644
--- a/web/setup.py
+++ b/web/setup.py
@@ -14,14 +14,10 @@ import argparse
 import json
 import os
 import sys
+import builtins
 from pgadmin.model import db, User, Version, ServerGroup, Server, \
     SCHEMA_VERSION as CURRENT_SCHEMA_VERSION
 
-if sys.version_info[0] >= 3:
-    import builtins
-else:
-    import __builtin__ as builtins
-
 # Grab the SERVER_MODE if it's been set by the runtime
 if 'SERVER_MODE' in globals():
     builtins.SERVER_MODE = globals()['SERVER_MODE']
