diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx
index 11e6dfe3..a50d4f44 100644
--- a/common/rfb/CSecurityTLS.cxx
+++ b/common/rfb/CSecurityTLS.cxx
@@ -66,6 +66,12 @@ StringParameter CSecurityTLS::X509CA("X509CA", "X509 CA certificate",
 StringParameter CSecurityTLS::X509CRL("X509CRL", "X509 CRL file",
                                      configdirfn("x509_crl.pem"),
                                      ConfViewer);
+StringParameter CSecurityTLS::X509CERT("X509CERT", "X509 client certificate",
+                                     configdirfn("x509_cert.pem"),
+                                     ConfViewer);
+StringParameter CSecurityTLS::X509KEY("X509KEY", "X509 client private key",
+                                     configdirfn("x509_key.pem"),
+                                     ConfViewer);
 
 static LogWriter vlog("TLS");
 
@@ -280,6 +286,8 @@ void CSecurityTLS::setParam()
 
     if (gnutls_certificate_set_x509_crl_file(cert_cred, X509CRL, GNUTLS_X509_FMT_PEM) < 0)
       vlog.error("Could not load user specified certificate revocation list");
+    if (gnutls_certificate_set_x509_key_file (cert_cred, X509CERT, X509KEY, GNUTLS_X509_FMT_PEM) < 0)
+      vlog.error("Could not load user specified client certificate");
 
     if (gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred) != GNUTLS_E_SUCCESS)
       throw AuthFailureException("gnutls_credentials_set failed");
diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h
index b9c345cf..271f0d69 100644
--- a/common/rfb/CSecurityTLS.h
+++ b/common/rfb/CSecurityTLS.h
@@ -44,6 +44,8 @@ namespace rfb {
 
     static StringParameter X509CA;
     static StringParameter X509CRL;
+    static StringParameter X509CERT;
+    static StringParameter X509KEY;
 
   protected:
     void shutdown();
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index 3c293fac..3ea03822 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -61,7 +61,7 @@ std::map<OptionsCallback*, void*> OptionsDialog::callbacks;
 static std::set<OptionsDialog *> instances;
 
 OptionsDialog::OptionsDialog()
-  : Fl_Window(580, 420, _("TigerVNC Options"))
+  : Fl_Window(580, 450, _("TigerVNC Options"))
 {
   int x, y;
   Fl_Navigation *navigation;
@@ -307,6 +307,8 @@ void OptionsDialog::loadOptions(void)
 #ifdef HAVE_GNUTLS
   caInput->value(CSecurityTLS::X509CA);
   crlInput->value(CSecurityTLS::X509CRL);
+  certInput->value(CSecurityTLS::X509CERT);
+  keyInput->value(CSecurityTLS::X509KEY);
 
   handleX509(encX509Checkbox, this);
 #endif
@@ -438,6 +440,8 @@ void OptionsDialog::storeOptions(void)
 
   CSecurityTLS::X509CA.setParam(caInput->value());
   CSecurityTLS::X509CRL.setParam(crlInput->value());
+  CSecurityTLS::X509CERT.setParam(certInput->value());
+  CSecurityTLS::X509KEY.setParam(keyInput->value());
 #endif
 
 #ifdef HAVE_NETTLE
@@ -730,6 +734,20 @@ void OptionsDialog::createSecurityPage(int tx, int ty, int tw, int th)
                             _("Path to X509 CRL file"));
     crlInput->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
     ty += INPUT_HEIGHT + TIGHT_MARGIN;
+
+    ty += INPUT_LABEL_OFFSET;
+    certInput = new Fl_Input(tx + INDENT, ty, 
+                           width - INDENT * 2, INPUT_HEIGHT,
+                           _("Path to X509 client certificate"));
+    certInput->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
+    ty += INPUT_HEIGHT + TIGHT_MARGIN;
+
+    ty += INPUT_LABEL_OFFSET;
+    keyInput = new Fl_Input(tx + INDENT, ty,
+                            width - INDENT * 2, INPUT_HEIGHT,
+                            _("Path to X509 client private key"));
+    keyInput->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
+    ty += INPUT_HEIGHT + TIGHT_MARGIN;
 #endif
 #ifdef HAVE_NETTLE
     encRSAAESCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
@@ -1096,9 +1114,13 @@ void OptionsDialog::handleX509(Fl_Widget* /*widget*/, void *data)
   if (dialog->encX509Checkbox->value()) {
     dialog->caInput->activate();
     dialog->crlInput->activate();
+    dialog->certInput->activate();
+    dialog->keyInput->activate();
   } else {
     dialog->caInput->deactivate();
     dialog->crlInput->deactivate();
+    dialog->certInput->deactivate();
+    dialog->keyInput->deactivate();
   }
 }
 
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
index be08620d..58dbba14 100644
--- a/vncviewer/OptionsDialog.h
+++ b/vncviewer/OptionsDialog.h
@@ -105,6 +105,8 @@ protected:
   Fl_Check_Button *encRSAAESCheckbox;
   Fl_Input *caInput;
   Fl_Input *crlInput;
+  Fl_Input *certInput;
+  Fl_Input *keyInput;
 
   Fl_Group *authenticationGroup;
   Fl_Check_Button *authNoneCheckbox;
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index 15ea4ee8..fc17b92b 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -177,6 +177,8 @@ static VoidParameter* parameterArray[] = {
 #ifdef HAVE_GNUTLS
   &CSecurityTLS::X509CA,
   &CSecurityTLS::X509CRL,
+  &CSecurityTLS::X509CERT,
+  &CSecurityTLS::X509KEY,
 #endif // HAVE_GNUTLS
   &SecurityClient::secTypes,
   /* Misc. */
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index 1a282126..4c6d6907 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -165,6 +165,20 @@ Path to certificate revocation list to use in conjunction with
 \fI~/.config/tigervnc/x509_crl.pem\fP.
 .
 .TP
+.B \-X509CERT \fIpath\fP
+Path to client certificate to use when authenticating client using any
+of the X509 security schemes (X509None, X509Vnc, etc.). Must be in PEM
+format. Default is \fI$XDG_CONFIG_HOME/tigervnc/x509_cert.pem\fP, or
+\fI~/.config/tigervnc/x509_cert.pem\fP.
+.
+.TP
+.B \-X509KEY \fIpath\fP
+Path to client private key to use in conjunction with
+\fB-X509CERT\fP. Must also be in PEM format. Default is
+\fI$XDG_CONFIG_HOME/tigervnc/x509_key.pem\fP, or
+\fI~/.config/tigervnc/x509_key.pem\fP.
+.
+.TP
 .B \-Shared
 When you make a connection to a VNC server, all other existing connections are
 normally closed.  This option requests that they be left open, allowing you to
