diff --git a/okcli/completion_cache.py b/okcli/completion_cache.py
new file mode 100644
index 0000000..a7f2e0c
--- /dev/null
+++ b/okcli/completion_cache.py
@@ -0,0 +1,18 @@
+import hashlib
+from os import path
+
+def completion_filename(user, host):
+    return hashlib.md5(("%s%s" % (user, host)).encode('utf-8')).hexdigest()
+
+def completion_cache_dir(config):
+    return path.join(path.dirname(config.filename), '.okcli_cache')
+
+def completion_cache_file(user, host, config):
+    return path.join(completion_cache_dir(config), completion_filename(user, host))
+
+def existing_completion_cache_file(user, host, config):
+    maybe_file = completion_cache_file(user, host, config)
+    if path.isfile(maybe_file):
+        return maybe_file
+    else:
+        return None
diff --git a/okcli/main.py b/okcli/main.py
index 282e6a2..5d451dd 100755
--- a/okcli/main.py
+++ b/okcli/main.py
@@ -42,6 +42,9 @@
 from .packages.special.main import NO_QUERY
 from .sqlcompleter import SQLCompleter
 from .sqlexecute import SQLExecute
+from .completion_cache import (existing_completion_cache_file,
+                               completion_cache_file,
+                               completion_cache_dir)
 
 click.disable_unicode_literals_warning = True
 try:
@@ -106,6 +109,7 @@ def __init__(self, sqlexecute=None, prompt=None,
         self.formatter = TabularOutputFormatter(
             format_name=c['main']['table_format'])
         self.syntax_style = c['main']['syntax_style']
+        self.cache_completions = c['main'].as_bool('cache_completions')
         self.cli_style = c['colors']
         self.wider_completion_menu = c['main'].as_bool('wider_completion_menu')
         c_ddl_warning = c['main'].as_bool('ddl_warning')
@@ -640,17 +644,31 @@ def refresh_completions(self, reset=False):
         if reset:
             with self._completer_lock:
                 self.completer.reset_completions()
+        status_message = 'Auto-completion refresh started in the background.'
+        if self.cache_completions:
+            maybe_cache = existing_completion_cache_file(self.sqlexecute.user, self.sqlexecute.host, self.config)
+            if maybe_cache is not None:
+              import pickle
+              status_message = "%s (using cache for now)" % status_message
+              with open(maybe_cache, 'rb') as compfile:
+                  new_completer = pickle.load(compfile)
+                  self._swap_completer_objects(new_completer)
         self.completion_refresher.refresh(
             self.sqlexecute, self._on_completions_refreshed,
             {'smart_completion': self.smart_completion,
              'supported_formats': self.formatter.supported_formats})
 
-        return [(None, None, None,
-                 'Auto-completion refresh started in the background.')]
+        return [(None, None, None, status_message)]
 
     def _on_completions_refreshed(self, new_completer):
         self._swap_completer_objects(new_completer)
 
+        if self.cache_completions:
+            import pickle
+            os.makedirs(completion_cache_dir(self.config), exist_ok=True)
+            with open(completion_cache_file(self.sqlexecute.user, self.sqlexecute.host, self.config), 'wb') as compfile:
+                pickle.dump(new_completer, compfile)
+
         if self.cli:
             # After refreshing, redraw the CLI to clear the statusbar
             # "Refreshing completions..." indicator
diff --git a/okcli/okclirc b/okcli/okclirc
index 90972b1..401877e 100644
--- a/okcli/okclirc
+++ b/okcli/okclirc
@@ -5,6 +5,11 @@
 # possible completions will be listed.
 smart_completion = True
 
+# Caches completions until they have been refreshed.
+# This makes sense when loading completions is not instantaneous
+# (depends on the amount of things in the database)
+cache_completions = False
+
 # Multi-line mode allows breaking up the sql statements into multiple lines. If
 # this is set to True, then the end of the statements must have a semi-colon.
 # If this is set to False then sql statements can't be split into multiple