diff --git a/gajim/common/connection.py b/gajim/common/connection.py
index 85703eb67..42528cabb 100644
--- a/gajim/common/connection.py
+++ b/gajim/common/connection.py
@@ -1835,17 +1835,6 @@ class Connection(CommonConnection, ConnectionHandlers):
         # disconnect from jabber server
         self.connection.send(p)
 
-    def change_password(self, password):
-        if not app.account_is_connected(self.name):
-            return
-        hostname = app.config.get_per('accounts', self.name, 'hostname')
-        username = app.config.get_per('accounts', self.name, 'name')
-        iq = nbxmpp.Iq(typ='set', to=hostname)
-        q = iq.setTag(nbxmpp.NS_REGISTER + ' query')
-        q.setTagData('username', username)
-        q.setTagData('password', password)
-        self.connection.send(iq)
-
     def get_password(self, callback, type_):
         if app.config.get_per('accounts', self.name, 'anonymous_auth') and \
         type_ != 'ANONYMOUS':
diff --git a/gajim/common/modules/register.py b/gajim/common/modules/register.py
new file mode 100644
index 000000000..6f52b57c5
--- /dev/null
+++ b/gajim/common/modules/register.py
@@ -0,0 +1,62 @@
+# This file is part of Gajim.
+#
+# Gajim is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; version 3 only.
+#
+# Gajim is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Gajim.  If not, see .
+
+# XEP-0077: In-Band Registration
+
+import logging
+import weakref
+
+import nbxmpp
+
+from gajim.common import app
+
+log = logging.getLogger('gajim.c.m.register')
+
+
+class Register:
+    def __init__(self, con):
+        self._con = con
+        self._account = con.name
+
+        self.handlers = []
+
+    def change_password(self, password, success_cb, error_cb):
+        if not app.account_is_connected(self._account):
+            return
+        hostname = app.config.get_per('accounts', self._account, 'hostname')
+        username = app.config.get_per('accounts', self._account, 'name')
+        iq = nbxmpp.Iq(typ='set', to=hostname)
+        q = iq.setTag(nbxmpp.NS_REGISTER + ' query')
+        q.setTagData('username', username)
+        q.setTagData('password', password)
+
+        weak_success_cb = weakref.WeakMethod(success_cb)
+        weak_error_cb = weakref.WeakMethod(error_cb)
+        log.info('Send password change')
+        self._con.connection.SendAndCallForResponse(
+            iq, self._change_password_response, {'success_cb': weak_success_cb,
+                                                 'error_cb': weak_error_cb})
+
+    def _change_password_response(self, con, stanza, success_cb, error_cb):
+        if not nbxmpp.isResultNode(stanza):
+            error = stanza.getErrorMsg()
+            log.info('Error: %s', error)
+            error_cb()(error)
+        else:
+            log.info('Password changed')
+            success_cb()()
+
+
+def get_instance(*args, **kwargs):
+    return Register(*args, **kwargs), 'Register'
diff --git a/gajim/data/gui/change_password_dialog.ui b/gajim/data/gui/change_password_dialog.ui
index 13ffe02a7..292334a4f 100644
--- a/gajim/data/gui/change_password_dialog.ui
+++ b/gajim/data/gui/change_password_dialog.ui
@@ -1,157 +1,56 @@
 
-
+
 
   
-  
diff --git a/gajim/data/style/gajim.css b/gajim/data/style/gajim.css
index fc0baf96d..b42354ebe 100644
--- a/gajim/data/style/gajim.css
+++ b/gajim/data/style/gajim.css
@@ -21,6 +21,8 @@
 	background-image: none;
 	}
 
+.dialog-margin > box { margin: 18px;}
+
 #MessageWindow, #RosterWindow paned { background-color:  @theme_base_color; }
 
 .chatcontrol-separator-top {margin-top: 5px;}
diff --git a/gajim/dialogs.py b/gajim/dialogs.py
index 205e99cb4..ead6e7d07 100644
--- a/gajim/dialogs.py
+++ b/gajim/dialogs.py
@@ -1058,41 +1058,6 @@ class SynchroniseSelectContactsDialog:
             iter_ = model.iter_next(iter_)
         self.dialog.destroy()
 
-class ChangePasswordDialog:
-    def __init__(self, account, on_response, transient_for=None):
-        # 'account' can be None if we are about to create our first one
-        if not account or app.connections[account].connected < 2:
-            ErrorDialog(_('You are not connected to the server'),
-                _('Without a connection, you can not change your password.'))
-            raise GajimGeneralException('You are not connected to the server')
-        self.account = account
-        self.on_response = on_response
-        self.xml = gtkgui_helpers.get_gtk_builder('change_password_dialog.ui')
-        self.dialog = self.xml.get_object('change_password_dialog')
-        self.dialog.set_transient_for(transient_for)
-        self.password1_entry = self.xml.get_object('password1_entry')
-        self.password2_entry = self.xml.get_object('password2_entry')
-        self.dialog.connect('response', self.on_dialog_response)
-
-        self.dialog.show_all()
-
-    def on_dialog_response(self, dialog, response):
-        if response != Gtk.ResponseType.OK:
-            dialog.destroy()
-            self.on_response(None)
-            return
-        password1 = self.password1_entry.get_text()
-        if not password1:
-            ErrorDialog(_('Invalid password'), _('You must enter a password.'))
-            return
-        password2 = self.password2_entry.get_text()
-        if password1 != password2:
-            ErrorDialog(_('Passwords do not match'),
-                _('The passwords typed in both fields must be identical.'))
-            return
-        dialog.destroy()
-        self.on_response(password1)
-
 
 #Action that can be done with an incoming list of contacts
 TRANSLATED_ACTION = {'add': _('add'), 'modify': _('modify'),
diff --git a/gajim/gtk/__init__.py b/gajim/gtk/__init__.py
index c901ac2e5..e21fc3645 100644
--- a/gajim/gtk/__init__.py
+++ b/gajim/gtk/__init__.py
@@ -51,6 +51,7 @@ from gajim.gtk.dialogs import ConfirmationDialog
 from gajim.gtk.dialogs import AspellDictError
 from gajim.gtk.dialogs import HigDialog
 from gajim.gtk.dialogs import SSLErrorDialog
+from gajim.gtk.dialogs import ChangePasswordDialog
 
 from gajim.gtk.about import AboutDialog
 from gajim.gtk.join_groupchat import JoinGroupchatWindow
diff --git a/gajim/gtk/dialogs.py b/gajim/gtk/dialogs.py
index 731fb7b4c..ea3feb5bc 100644
--- a/gajim/gtk/dialogs.py
+++ b/gajim/gtk/dialogs.py
@@ -13,6 +13,7 @@
 # along with Gajim. If not, see .
 
 from gi.repository import Gtk
+from gi.repository import Gdk
 
 from gajim.common import app
 from gajim.common import helpers
@@ -931,3 +932,57 @@ class SSLErrorDialog(ConfirmationDialogDoubleCheck):
 
     def on_cert_clicked(self, button):
         CertificatDialog(self, self.account, self.cert)
+
+
+class ChangePasswordDialog(Gtk.Dialog):
+    def __init__(self, account, success_cb, transient_for):
+        flags = Gtk.DialogFlags.DESTROY_WITH_PARENT
+        super().__init__(_('Change Password'), None, flags)
+
+        self._account = account
+        self._success_cb = success_cb
+
+        self._builder = get_builder('change_password_dialog.ui')
+        self.get_content_area().add(
+            self._builder.get_object('change_password_box'))
+        self._password1_entry = self._builder.get_object('password1_entry')
+        self._password2_entry = self._builder.get_object('password2_entry')
+        self._error_label = self._builder.get_object('error_label')
+
+        self.set_transient_for(transient_for)
+
+        self.add_button(_('_OK'), Gtk.ResponseType.OK)
+        self.set_default_response(Gtk.ResponseType.OK)
+        self.get_style_context().add_class('dialog-margin')
+        self.connect('response', self._on_dialog_response)
+        self.show_all()
+
+    def _on_dialog_response(self, dialog, response):
+        if response != Gtk.ResponseType.OK:
+            self.destroy()
+            return
+
+        password1 = self._password1_entry.get_text()
+        if not password1:
+            self._error_label.set_text(_('You must enter a password'))
+            return
+        password2 = self._password2_entry.get_text()
+        if password1 != password2:
+            self._error_label.set_text(_('Passwords do not match'))
+            return
+
+        self._password1_entry.set_sensitive(False)
+        self._password2_entry.set_sensitive(False)
+
+        con = app.connections[self._account]
+        con.get_module('Register').change_password(
+            password1, self._on_success, self._on_error)
+
+    def _on_success(self):
+        self._success_cb(self._password1_entry.get_text())
+        self.destroy()
+
+    def _on_error(self, error_text):
+        self._error_label.set_text(error_text)
+        self._password1_entry.set_sensitive(True)
+        self._password2_entry.set_sensitive(True)
diff --git a/gajim/options_dialog.py b/gajim/options_dialog.py
index a5e66ab5b..5f06a17f8 100644
--- a/gajim/options_dialog.py
+++ b/gajim/options_dialog.py
@@ -6,6 +6,8 @@ from gajim.common.const import OptionKind, OptionType
 from gajim.common.exceptions import GajimGeneralException
 from gajim import dialogs
 from gajim.gtk import ErrorDialog
+from gajim.gtk import ChangePasswordDialog
+
 
 class OptionsDialog(Gtk.ApplicationWindow):
     def __init__(self, parent, title, flags, options, account,
@@ -530,16 +532,14 @@ class ChangePasswordOption(DialogOption):
 
     def show_dialog(self, parent):
         try:
-            self.change_dialog = dialogs.ChangePasswordDialog(
+            self.change_dialog = ChangePasswordDialog(
                 self.account, self.on_changed, parent)
         except GajimGeneralException:
             return
-        self.change_dialog.dialog.set_modal(True)
+        self.change_dialog.set_modal(True)
 
     def on_changed(self, new_password):
-        if new_password is not None:
-            app.connections[self.account].change_password(new_password)
-            self.set_value(new_password)
+        self.set_value(new_password)
 
     def set_activatable(self, name, value):
         activatable = False