password_encryption, default and 'plain' support

Started by Heikki Linnakangasover 8 years ago19 messages
#1Heikki Linnakangas
hlinnaka@iki.fi

Hi,

In various threads on SCRAM, we've skirted around the question of
whether we should still allow storing passwords in plaintext. I've
avoided discussing that in those other threads, because it's been an
orthogonal question, but it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

Another question that's been touched upon but not explicitly discussed,
is whether we should change the default to "scram-sha-256". I propose
that we do that as well. If you need to stick to md5, e.g. because you
use drivers that don't support SCRAM yet, you can change it in
postgresql.conf, but the majority of installations that use modern
clients will be more secure by default.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Magnus Hagander
magnus@hagander.net
In reply to: Heikki Linnakangas (#1)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 1:31 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

Hi,

In various threads on SCRAM, we've skirted around the question of whether
we should still allow storing passwords in plaintext. I've avoided
discussing that in those other threads, because it's been an orthogonal
question, but it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

Is there any usecase at all for it today?

+1 for getting rid of it :)

Another question that's been touched upon but not explicitly discussed, is
whether we should change the default to "scram-sha-256". I propose that we
do that as well. If you need to stick to md5, e.g. because you use drivers
that don't support SCRAM yet, you can change it in postgresql.conf, but the
majority of installations that use modern clients will be more secure by
default.

Much as that's going to cause issues for some people, I think it's worth
doing. We should probably put something specific in the release notes
mentioning the error message you get in libpq, and possibly some of the
other most common drivers.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#3Michael Paquier
michael.paquier@gmail.com
In reply to: Magnus Hagander (#2)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 8:38 PM, Magnus Hagander <magnus@hagander.net> wrote:

On Wed, May 3, 2017 at 1:31 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In various threads on SCRAM, we've skirted around the question of whether
we should still allow storing passwords in plaintext. I've avoided
discussing that in those other threads, because it's been an orthogonal
question, but it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

Is there any usecase at all for it today?

For developers running applications on top of Postgres?

Another question that's been touched upon but not explicitly discussed, is
whether we should change the default to "scram-sha-256". I propose that we
do that as well. If you need to stick to md5, e.g. because you use drivers
that don't support SCRAM yet, you can change it in postgresql.conf, but the
majority of installations that use modern clients will be more secure by
default.

Much as that's going to cause issues for some people, I think it's worth
doing. We should probably put something specific in the release notes
mentioning the error message you get in libpq, and possibly some of the
other most common drivers.

My original view on the matter was, and is still, to wait for one or
two releases before switching the default to scram.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Magnus Hagander
magnus@hagander.net
In reply to: Michael Paquier (#3)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 2:25 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Wed, May 3, 2017 at 8:38 PM, Magnus Hagander <magnus@hagander.net>
wrote:

On Wed, May 3, 2017 at 1:31 PM, Heikki Linnakangas <hlinnaka@iki.fi>

wrote:

In various threads on SCRAM, we've skirted around the question of

whether

we should still allow storing passwords in plaintext. I've avoided
discussing that in those other threads, because it's been an orthogonal
question, but it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

Is there any usecase at all for it today?

For developers running applications on top of Postgres?

I don't get it. How does password_encryption=plain help them?

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#5Robert Haas
robertmhaas@gmail.com
In reply to: Heikki Linnakangas (#1)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In various threads on SCRAM, we've skirted around the question of whether we
should still allow storing passwords in plaintext. I've avoided discussing
that in those other threads, because it's been an orthogonal question, but
it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Another question that's been touched upon but not explicitly discussed, is
whether we should change the default to "scram-sha-256". I propose that we
do that as well. If you need to stick to md5, e.g. because you use drivers
that don't support SCRAM yet, you can change it in postgresql.conf, but the
majority of installations that use modern clients will be more secure by
default.

I think that we should investigate how many connectors have support
for SCRAM or are likely to do so by the time v10 is released. A *lot*
of people are using connectors that are not based on libpq, especially
JDBC but I think many of the others as well. If most of those are
going to support SCRAM by the time v10 comes out, cool, but if not,
maybe it's wise to hold off for a release before flipping the default.
Not sure.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#5)
Re: password_encryption, default and 'plain' support

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Is it possible that there are still client libraries that don't support
password encryption at all? If so, are we willing to break them?
I'd say "yes" but it's worth thinking about.

Another question that's been touched upon but not explicitly discussed, is
whether we should change the default to "scram-sha-256". I propose that we
do that as well. If you need to stick to md5, e.g. because you use drivers
that don't support SCRAM yet, you can change it in postgresql.conf, but the
majority of installations that use modern clients will be more secure by
default.

I think that we should investigate how many connectors have support
for SCRAM or are likely to do so by the time v10 is released. A *lot*
of people are using connectors that are not based on libpq, especially
JDBC but I think many of the others as well.

Yes, there's an awful lot out there besides libpq. I do not think it is
reasonable at all to change this default in v10. Maybe v11, depending on
how fast JDBC et al move. If we try to force it in v10, we are going to
get a heck of a lot of complaints about "I changed my password and now
I can't get in at all using <x>", where <x> is also going to include
back-rev psql. (And I'm not even considering the possibility of nasty
bugs in the SCRAM code.) Making SCRAM the default in the first version
where it's even available is moving way too fast IMO.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Tom Lane (#6)
Re: password_encryption, default and 'plain' support

On 05/03/2017 07:14 PM, Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Is it possible that there are still client libraries that don't support
password encryption at all? If so, are we willing to break them?
I'd say "yes" but it's worth thinking about.

That doesn't make sense. The client doesn't even know what
password_encryption is set to. I think you're confusing
password_encryption='plain' with the plaintext "password" authentication
method.

If the server has an MD5 hash stored in pg_authid, the server will ask
the client to do MD5 authentication. If the server has a SCRAM verifier
in pg_authid, it will ask the client to do SCRAM authentication. If the
server has a plaintext password in pg_authid, it will also ask the
client to do SCRAM authentication (it could ask for MD5 authentication,
but as the code stands, it will ask for SCRAM).

The server will only ask the client to do plaintext password
authentication, if you put "password" as the authentication method in
pg_hba.conf. But that works regardless of what password_encryption is
set to.

No, I don't think there's any valid reason to store passwords in
plaintext anymore. In theory, you could use either MD5 or SCRAM
authentication with a plaintext password, which would be an advantage,
but we don't provide an option for that.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Tom Lane
tgl@sss.pgh.pa.us
In reply to: Heikki Linnakangas (#7)
Re: password_encryption, default and 'plain' support

Heikki Linnakangas <hlinnaka@iki.fi> writes:

On 05/03/2017 07:14 PM, Tom Lane wrote:

Is it possible that there are still client libraries that don't support
password encryption at all? If so, are we willing to break them?
I'd say "yes" but it's worth thinking about.

That doesn't make sense. The client doesn't even know what
password_encryption is set to. I think you're confusing
password_encryption='plain' with the plaintext "password" authentication
method.

Ah, you're right.

If the server has an MD5 hash stored in pg_authid, the server will ask
the client to do MD5 authentication. If the server has a SCRAM verifier
in pg_authid, it will ask the client to do SCRAM authentication. If the
server has a plaintext password in pg_authid, it will also ask the
client to do SCRAM authentication (it could ask for MD5 authentication,
but as the code stands, it will ask for SCRAM).

Um. That would be a backwards compatibility break ... but it doesn't
matter if we get rid of the option to store in plaintext.

The other question I can think to ask is what will happen during
pg_upgrade, given an existing installation with one or more passwords
stored plain. If the answer is "silently convert to MD5", I'd be
good with that.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Magnus Hagander
magnus@hagander.net
In reply to: Robert Haas (#5)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 5:52 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

In various threads on SCRAM, we've skirted around the question of

whether we

should still allow storing passwords in plaintext. I've avoided

discussing

that in those other threads, because it's been an orthogonal question,

but

it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Another question that's been touched upon but not explicitly discussed,

is

whether we should change the default to "scram-sha-256". I propose that

we

do that as well. If you need to stick to md5, e.g. because you use

drivers

that don't support SCRAM yet, you can change it in postgresql.conf, but

the

majority of installations that use modern clients will be more secure by
default.

I think that we should investigate how many connectors have support
for SCRAM or are likely to do so by the time v10 is released. A *lot*
of people are using connectors that are not based on libpq, especially
JDBC but I think many of the others as well. If most of those are
going to support SCRAM by the time v10 comes out, cool, but if not,
maybe it's wise to hold off for a release before flipping the default.
Not sure.

From the traffic on the list it sounds like the JDBC people are working on
it already -- hopefully they will have something in time.

It might make sense to ping other "major drivers" people as well -- such as
maybe npgsql. What else?

A good approach might be to change the default now, before beta. Then if
drivers don't change, or if we get a lot of pushback from beta testers, we
change it back before release. But if we don't change it, we will not know
how big the impact would be...

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#10Michael Paquier
michael.paquier@gmail.com
In reply to: Magnus Hagander (#4)
Re: password_encryption, default and 'plain' support

On Wed, May 3, 2017 at 9:57 PM, Magnus Hagander <magnus@hagander.net> wrote:

On Wed, May 3, 2017 at 2:25 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Wed, May 3, 2017 at 8:38 PM, Magnus Hagander <magnus@hagander.net>
wrote:

On Wed, May 3, 2017 at 1:31 PM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

In various threads on SCRAM, we've skirted around the question of
whether
we should still allow storing passwords in plaintext. I've avoided
discussing that in those other threads, because it's been an orthogonal
question, but it's a good question and we should discuss it.

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

Is there any usecase at all for it today?

For developers running applications on top of Postgres?

I don't get it. How does password_encryption=plain help them?

Sanity checks at development stage of web applications to make sure
that the password strength automatically generated by the application
at first login is strong enough. I personally found that helpful for
this purpose.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Tom Lane (#8)
1 attachment(s)
Re: password_encryption, default and 'plain' support

On 05/03/2017 08:40 PM, Tom Lane wrote:

The other question I can think to ask is what will happen during
pg_upgrade, given an existing installation with one or more passwords
stored plain. If the answer is "silently convert to MD5", I'd be
good with that.

Yes, it will silently convert to MD5. That happened even on earlier
versions, if you had password_encryption=on in the new cluster (which
was the default).

I'm planning to go ahead with the attached patch for this (removing
password_encryption='plain' support, but keeping the default as 'md5').

- Heikki

Attachments:

0001-Remove-support-for-password_encryption-off-plain.patchtext/x-diff; name=0001-Remove-support-for-password_encryption-off-plain.patchDownload
From 62d42e07fe09dcb8586620ee66b1567a8f002f27 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu, 4 May 2017 14:31:45 +0300
Subject: [PATCH 1/1] Remove support for password_encryption='off' / 'plain'.

Storing passwords in plaintext hasn't been a good idea for a very long
time, if ever. Now seems like a good time to finally forbid it, since we're
messing with this in PostgreSQL 10 anyway.

This also removes the CREATE/ALTER USER UNENCRYPTED PASSSWORD 'foo' syntax,
since storing passwords unencrypted is no longer supported. ENCRYPTED
PASSWORD 'foo' is still accepted, but ENCRYPTED is now just a noise-word,
it does the same as just PASSWORD 'foo'.

Likewise, remove the --unencrypted option from createuser, but accept
--encrypted as a no-op for backwards-compatibility. AFAICS, --encrypted was
a no-op even before this patch, because createuser encrypted the password
before sending it to the server even if --encrypted was not specified. It
added the ENCRYPTED keyword to the SQL command, but since the password was
already in encrypted form, it didn't matter. The documentation was not
clear on whether that was intended or not, but the point is moot now.

Also, while password_encryption='on' is still accepted as an alias for
'md5', it is now marked as hidden, so that it is not listed as an accepted
value in error hints, for example. That's not directly related to removing
'plain', but it seems better this way.

Discussion: https://www.postgresql.org/message-id/16e9b768-fd78-0b12-cfc1-7b6b7f238fde@iki.fi
---
 doc/src/sgml/config.sgml                  |  18 +++--
 doc/src/sgml/ref/alter_role.sgml          |   6 +-
 doc/src/sgml/ref/alter_user.sgml          |   2 +-
 doc/src/sgml/ref/create_group.sgml        |   2 +-
 doc/src/sgml/ref/create_role.sgml         |  34 +++-----
 doc/src/sgml/ref/create_user.sgml         |   2 +-
 doc/src/sgml/ref/createuser.sgml          |  21 +----
 src/backend/commands/user.c               |  34 ++------
 src/backend/libpq/auth-scram.c            |  20 +----
 src/backend/libpq/auth.c                  |  26 ++----
 src/backend/libpq/crypt.c                 | 126 +++++++++---------------------
 src/backend/parser/gram.y                 |  14 +++-
 src/backend/utils/misc/guc.c              |  10 +--
 src/bin/psql/tab-complete.c               |  25 ++----
 src/bin/scripts/createuser.c              |  46 ++++-------
 src/include/libpq/crypt.h                 |   9 ++-
 src/interfaces/libpq/fe-auth.c            |   3 +-
 src/test/authentication/t/001_password.pl |  10 +--
 src/test/regress/expected/password.out    |  31 ++++----
 src/test/regress/sql/password.sql         |  23 +++---
 20 files changed, 154 insertions(+), 308 deletions(-)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 0b9e3002fb..20bc3c61b1 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1188,14 +1188,16 @@ include_dir 'conf.d'
       <listitem>
        <para>
         When a password is specified in <xref linkend="sql-createrole"> or
-        <xref linkend="sql-alterrole"> without writing either <literal>ENCRYPTED</>
-        or <literal>UNENCRYPTED</>, this parameter determines whether the
-        password is to be encrypted. The default value is <literal>md5</>, which
-        stores the password as an MD5 hash. Setting this to <literal>plain</> stores
-        it in plaintext. <literal>on</> and <literal>off</> are also accepted, as
-        aliases for <literal>md5</> and <literal>plain</>, respectively.  Setting
-        this parameter to <literal>scram-sha-256</> will encrypt the password
-        with SCRAM-SHA-256.
+        <xref linkend="sql-alterrole">, this parameter determines the algorithm
+        to use to encrypt the password. The default value is <literal>md5</>,
+        which stores the password as an MD5 hash (<literal>on</> is also
+        accepted, as alias for <literal>md5</>). Setting this parameter to
+        <literal>scram-sha-256</> will encrypt the password with SCRAM-SHA-256.
+       </para>
+       <para>
+        Note that older clients might lack support for the SCRAM authentication
+        mechanism, and hence not work with passwords encrypted with
+        SCRAM-SHA-256.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml
index 37fcfb926c..8cd8602bc4 100644
--- a/doc/src/sgml/ref/alter_role.sgml
+++ b/doc/src/sgml/ref/alter_role.sgml
@@ -33,7 +33,7 @@ ALTER ROLE <replaceable class="PARAMETER">role_specification</replaceable> [ WIT
     | REPLICATION | NOREPLICATION
     | BYPASSRLS | NOBYPASSRLS
     | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
-    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+    | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
     | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
 
 ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
@@ -168,9 +168,7 @@ ALTER ROLE { <replaceable class="PARAMETER">role_specification</replaceable> | A
       <term><literal>BYPASSRLS</literal></term>
       <term><literal>NOBYPASSRLS</literal></term>
       <term><literal>CONNECTION LIMIT</literal> <replaceable class="parameter">connlimit</replaceable></term>
-      <term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
-      <term><literal>ENCRYPTED</></term>
-      <term><literal>UNENCRYPTED</></term>
+      <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
       <term><literal>VALID UNTIL</literal> '<replaceable class="parameter">timestamp</replaceable>'</term>
       <listitem>
        <para>
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 5962a8e166..9b8a39b376 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -33,7 +33,7 @@ ALTER USER <replaceable class="PARAMETER">role_specification</replaceable> [ WIT
     | REPLICATION | NOREPLICATION
     | BYPASSRLS | NOBYPASSRLS
     | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
-    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+    | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
     | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
 
 ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
diff --git a/doc/src/sgml/ref/create_group.sgml b/doc/src/sgml/ref/create_group.sgml
index 1d5cc9b596..158617cb93 100644
--- a/doc/src/sgml/ref/create_group.sgml
+++ b/doc/src/sgml/ref/create_group.sgml
@@ -30,7 +30,7 @@ CREATE GROUP <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <repla
     | CREATEROLE | NOCREATEROLE
     | INHERIT | NOINHERIT
     | LOGIN | NOLOGIN
-    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+    | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
     | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
     | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
     | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]
diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml
index 99d1c8336c..4e40cd21ef 100644
--- a/doc/src/sgml/ref/create_role.sgml
+++ b/doc/src/sgml/ref/create_role.sgml
@@ -33,7 +33,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
     | REPLICATION | NOREPLICATION
     | BYPASSRLS | NOBYPASSRLS
     | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
-    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+    | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
     | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
     | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
     | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]
@@ -207,7 +207,7 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
      </varlistentry>
 
      <varlistentry>
-      <term><literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
+      <term>[ <literal>ENCRYPTED</> ] <literal>PASSWORD</> <replaceable class="parameter">password</replaceable></term>
       <listitem>
        <para>
         Sets the role's password.  (A password is only of use for
@@ -219,30 +219,18 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
         user.  A null password can optionally be written explicitly as
         <literal>PASSWORD NULL</literal>.
        </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
-      <term><literal>ENCRYPTED</></term>
-      <term><literal>UNENCRYPTED</></term>
-      <listitem>
        <para>
-        These key words control whether the password is stored
-        encrypted in the system catalogs.  (If neither is specified,
-        the default behavior is determined by the configuration
-        parameter <xref linkend="guc-password-encryption">.)  If the
-        presented password string is already in MD5-encrypted or
-        SCRAM-encrypted format, then it is stored encrypted as-is,
-        regardless of whether <literal>ENCRYPTED</> or <literal>UNENCRYPTED</>
-        is specified (since the system cannot decrypt the specified encrypted
-        password string).  This allows reloading of encrypted passwords
+        The password is always stored encrypted in the system catalogs. The
+        <literal>ENCRYPTED</> keyword has no effect, but is accepted for
+        backwards-compatibility. The method of encryption is determined
+        by the configuration parameter <xref linkend="guc-password-encryption">.
+        If the presented password string is already in MD5-encrypted or
+        SCRAM-encrypted format, then it is stored as-is regardless of
+        <varname>password_encryption</> (since the system cannot decrypt
+        the specified encrypted password string, to encrypt it in a
+        different format).  This allows reloading of encrypted passwords
         during dump/restore.
        </para>
-
-       <para>
-        Note that older clients might lack support for the SCRAM
-        authentication mechanism.
-       </para>
       </listitem>
      </varlistentry>
 
diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml
index 574604f796..8a596eec9f 100644
--- a/doc/src/sgml/ref/create_user.sgml
+++ b/doc/src/sgml/ref/create_user.sgml
@@ -33,7 +33,7 @@ CREATE USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
     | REPLICATION | NOREPLICATION
     | BYPASSRLS | NOBYPASSRLS
     | CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
-    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
+    | [ ENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
     | VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
     | IN ROLE <replaceable class="PARAMETER">role_name</replaceable> [, ...]
     | IN GROUP <replaceable class="PARAMETER">role_name</replaceable> [, ...]
diff --git a/doc/src/sgml/ref/createuser.sgml b/doc/src/sgml/ref/createuser.sgml
index 4332008c68..07e48c20c1 100644
--- a/doc/src/sgml/ref/createuser.sgml
+++ b/doc/src/sgml/ref/createuser.sgml
@@ -124,8 +124,8 @@ PostgreSQL documentation
       <term><option>--encrypted</></term>
       <listitem>
        <para>
-        Encrypts the user's password stored in the database. If not
-        specified, the default password behavior is used.
+        This option is obsolete but still accepted for backwards
+        compatibility.
        </para>
       </listitem>
      </varlistentry>
@@ -205,17 +205,6 @@ PostgreSQL documentation
      </varlistentry>
 
      <varlistentry>
-      <term><option>-N</></term>
-      <term><option>--unencrypted</></term>
-      <listitem>
-       <para>
-        Does not encrypt the user's password stored in the database. If
-        not specified, the default password behavior is used.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry>
       <term><option>-P</></term>
       <term><option>--pwprompt</></term>
       <listitem>
@@ -481,11 +470,7 @@ PostgreSQL documentation
 </screen>
     In the above example, the new password isn't actually echoed when typed,
     but we show what was typed for clarity.  As you see, the password is
-    encrypted before it is sent to the client.  If the option <option>--unencrypted</option>
-    is used, the password <emphasis>will</> appear in the echoed command
-    (and possibly also in the server log and elsewhere),
-    so you don't want to use <option>-e</> in that case, if
-    anyone else can see your screen.
+    encrypted before it is sent to the client.
    </para>
  </refsect1>
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index c719682274..36d5f40f06 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -80,7 +80,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	ListCell   *item;
 	ListCell   *option;
 	char	   *password = NULL;	/* user password */
-	int			password_type = Password_encryption;
 	bool		issuper = false;	/* Make the user a superuser? */
 	bool		inherit = true; /* Auto inherit privileges? */
 	bool		createrole = false;		/* Can this user create roles? */
@@ -128,9 +127,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 	{
 		DefElem    *defel = (DefElem *) lfirst(option);
 
-		if (strcmp(defel->defname, "password") == 0 ||
-			strcmp(defel->defname, "encryptedPassword") == 0 ||
-			strcmp(defel->defname, "unencryptedPassword") == 0)
+		if (strcmp(defel->defname, "password") == 0)
 		{
 			if (dpassword)
 				ereport(ERROR,
@@ -138,15 +135,6 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 						 errmsg("conflicting or redundant options"),
 						 parser_errposition(pstate, defel->location)));
 			dpassword = defel;
-			if (strcmp(defel->defname, "encryptedPassword") == 0)
-			{
-				if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256)
-					password_type = PASSWORD_TYPE_SCRAM_SHA_256;
-				else
-					password_type = PASSWORD_TYPE_MD5;
-			}
-			else if (strcmp(defel->defname, "unencryptedPassword") == 0)
-				password_type = PASSWORD_TYPE_PLAINTEXT;
 		}
 		else if (strcmp(defel->defname, "sysid") == 0)
 		{
@@ -400,7 +388,8 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
 		/* Encrypt the password to the requested format. */
 		char	   *shadow_pass;
 
-		shadow_pass = encrypt_password(password_type, stmt->role, password);
+		shadow_pass = encrypt_password(Password_encryption, stmt->role,
+									   password);
 		new_record[Anum_pg_authid_rolpassword - 1] =
 			CStringGetTextDatum(shadow_pass);
 	}
@@ -503,7 +492,6 @@ AlterRole(AlterRoleStmt *stmt)
 	ListCell   *option;
 	char	   *rolename = NULL;
 	char	   *password = NULL;	/* user password */
-	int			password_type = Password_encryption;
 	int			issuper = -1;	/* Make the user a superuser? */
 	int			inherit = -1;	/* Auto inherit privileges? */
 	int			createrole = -1;	/* Can this user create roles? */
@@ -537,24 +525,13 @@ AlterRole(AlterRoleStmt *stmt)
 	{
 		DefElem    *defel = (DefElem *) lfirst(option);
 
-		if (strcmp(defel->defname, "password") == 0 ||
-			strcmp(defel->defname, "encryptedPassword") == 0 ||
-			strcmp(defel->defname, "unencryptedPassword") == 0)
+		if (strcmp(defel->defname, "password") == 0)
 		{
 			if (dpassword)
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
 						 errmsg("conflicting or redundant options")));
 			dpassword = defel;
-			if (strcmp(defel->defname, "encryptedPassword") == 0)
-			{
-				if (Password_encryption == PASSWORD_TYPE_SCRAM_SHA_256)
-					password_type = PASSWORD_TYPE_SCRAM_SHA_256;
-				else
-					password_type = PASSWORD_TYPE_MD5;
-			}
-			else if (strcmp(defel->defname, "unencryptedPassword") == 0)
-				password_type = PASSWORD_TYPE_PLAINTEXT;
 		}
 		else if (strcmp(defel->defname, "superuser") == 0)
 		{
@@ -809,7 +786,8 @@ AlterRole(AlterRoleStmt *stmt)
 		/* Encrypt the password to the requested format. */
 		char	   *shadow_pass;
 
-		shadow_pass = encrypt_password(password_type, rolename, password);
+		shadow_pass = encrypt_password(Password_encryption, rolename,
+									   password);
 		new_record[Anum_pg_authid_rolpassword - 1] =
 			CStringGetTextDatum(shadow_pass);
 		new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 6e7a140582..cd4ede08f3 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -199,27 +199,11 @@ pg_be_scram_init(const char *username, const char *shadow_pass)
 				got_verifier = false;
 			}
 		}
-		else if (password_type == PASSWORD_TYPE_PLAINTEXT)
-		{
-			/*
-			 * The stored password is in plain format.  Generate a fresh SCRAM
-			 * verifier from it, and proceed with that.
-			 */
-			char	   *verifier;
-
-			verifier = pg_be_scram_build_verifier(shadow_pass);
-
-			(void) parse_scram_verifier(verifier, &state->iterations, &state->salt,
-										state->StoredKey, state->ServerKey);
-			pfree(verifier);
-
-			got_verifier = true;
-		}
 		else
 		{
 			/*
-			 * The user doesn't have SCRAM verifier, nor could we generate
-			 * one. (You cannot do SCRAM authentication with an MD5 hash.)
+			 * The user doesn't have SCRAM verifier. (You cannot do SCRAM
+			 * authentication with an MD5 hash.)
 			 */
 			state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier."),
 										state->username);
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index ab4be21943..6d3ff68607 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -754,17 +754,13 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
 	shadow_pass = get_role_password(port->user_name, logdetail);
 
 	/*
-	 * If the user does not exist, or has no password, we still go through the
-	 * motions of authentication, to avoid revealing to the client that the
-	 * user didn't exist.  If 'md5' is allowed, we choose whether to use 'md5'
-	 * or 'scram-sha-256' authentication based on current password_encryption
-	 * setting.  The idea is that most genuine users probably have a password
-	 * of that type, if we pretend that this user had a password of that type,
-	 * too, it "blends in" best.
-	 *
-	 * If the user had a password, but it was expired, we'll use the details
-	 * of the expired password for the authentication, but report it as
-	 * failure to the client even if correct password was given.
+	 * If the user does not exist, or has no password or it's expired, we
+	 * still go through the motions of authentication, to avoid revealing to
+	 * the client that the user didn't exist.  If 'md5' is allowed, we choose
+	 * whether to use 'md5' or 'scram-sha-256' authentication based on
+	 * current password_encryption setting.  The idea is that most genuine
+	 * users probably have a password of that type, and if we pretend that
+	 * this user had a password of that type, too, it "blends in" best.
 	 */
 	if (!shadow_pass)
 		pwtype = Password_encryption;
@@ -775,21 +771,15 @@ CheckPWChallengeAuth(Port *port, char **logdetail)
 	 * If 'md5' authentication is allowed, decide whether to perform 'md5' or
 	 * 'scram-sha-256' authentication based on the type of password the user
 	 * has.  If it's an MD5 hash, we must do MD5 authentication, and if it's
-	 * a SCRAM verifier, we must do SCRAM authentication.  If it's stored in
-	 * plaintext, we could do either one, so we opt for the more secure
-	 * mechanism, SCRAM.
+	 * a SCRAM verifier, we must do SCRAM authentication.
 	 *
 	 * If MD5 authentication is not allowed, always use SCRAM.  If the user
 	 * had an MD5 password, CheckSCRAMAuth() will fail.
 	 */
 	if (port->hba->auth_method == uaMD5 && pwtype == PASSWORD_TYPE_MD5)
-	{
 		auth_result = CheckMD5Auth(port, shadow_pass, logdetail);
-	}
 	else
-	{
 		auth_result = CheckSCRAMAuth(port, shadow_pass, logdetail);
-	}
 
 	if (shadow_pass)
 		pfree(shadow_pass);
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 9fe79b4894..e7a6b04fb5 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -109,9 +109,8 @@ get_password_type(const char *shadow_pass)
  * Given a user-supplied password, convert it into a verifier of
  * 'target_type' kind.
  *
- * If the password looks like a valid MD5 hash, it is stored as it is.
- * We cannot reverse the hash, so even if the caller requested a plaintext
- * plaintext password, the MD5 hash is returned.
+ * If the password is already in encrypted form, we cannot reverse the
+ * hash, so it is stored as it is regardless of the requested type.
  */
 char *
 encrypt_password(PasswordType target_type, const char *role,
@@ -120,54 +119,30 @@ encrypt_password(PasswordType target_type, const char *role,
 	PasswordType guessed_type = get_password_type(password);
 	char	   *encrypted_password;
 
-	switch (target_type)
+	if (guessed_type != PASSWORD_TYPE_PLAINTEXT)
 	{
-		case PASSWORD_TYPE_PLAINTEXT:
-
-			/*
-			 * We cannot convert a hashed password back to plaintext, so just
-			 * store the password as it was, whether it was hashed or not.
-			 */
-			return pstrdup(password);
+		/*
+		 * Cannot convert an already-encrypted password from one
+		 * format to another, so return it as it is.
+		 */
+		return pstrdup(password);
+	}
 
+	switch (target_type)
+	{
 		case PASSWORD_TYPE_MD5:
-			switch (guessed_type)
-			{
-				case PASSWORD_TYPE_PLAINTEXT:
-					encrypted_password = palloc(MD5_PASSWD_LEN + 1);
-
-					if (!pg_md5_encrypt(password, role, strlen(role),
-										encrypted_password))
-						elog(ERROR, "password encryption failed");
-					return encrypted_password;
+			encrypted_password = palloc(MD5_PASSWD_LEN + 1);
 
-				case PASSWORD_TYPE_SCRAM_SHA_256:
-
-					/*
-					 * cannot convert a SCRAM verifier to an MD5 hash, so fall
-					 * through to save the SCRAM verifier instead.
-					 */
-				case PASSWORD_TYPE_MD5:
-					return pstrdup(password);
-			}
-			break;
+			if (!pg_md5_encrypt(password, role, strlen(role),
+								encrypted_password))
+				elog(ERROR, "password encryption failed");
+			return encrypted_password;
 
 		case PASSWORD_TYPE_SCRAM_SHA_256:
-			switch (guessed_type)
-			{
-				case PASSWORD_TYPE_PLAINTEXT:
-					return pg_be_scram_build_verifier(password);
-
-				case PASSWORD_TYPE_MD5:
+			return pg_be_scram_build_verifier(password);
 
-					/*
-					 * cannot convert an MD5 hash to a SCRAM verifier, so fall
-					 * through to save the MD5 hash instead.
-					 */
-				case PASSWORD_TYPE_SCRAM_SHA_256:
-					return pstrdup(password);
-			}
-			break;
+		case PASSWORD_TYPE_PLAINTEXT:
+			elog(ERROR, "cannot encrypt password with 'plaintext'");
 	}
 
 	/*
@@ -197,10 +172,17 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
 {
 	int			retval;
 	char		crypt_pwd[MD5_PASSWD_LEN + 1];
-	char		crypt_pwd2[MD5_PASSWD_LEN + 1];
 
 	Assert(md5_salt_len > 0);
 
+	if (get_password_type(shadow_pass) != PASSWORD_TYPE_MD5)
+	{
+		/* incompatible password hash format. */
+		*logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
+							  role);
+		return STATUS_ERROR;
+	}
+
 	/*
 	 * Compute the correct answer for the MD5 challenge.
 	 *
@@ -208,40 +190,12 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
 	 * below: the only possible error is out-of-memory, which is unlikely, and
 	 * if it did happen adding a psprintf call would only make things worse.
 	 */
-	switch (get_password_type(shadow_pass))
+	/* stored password already encrypted, only do salt */
+	if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
+						md5_salt, md5_salt_len,
+						crypt_pwd))
 	{
-		case PASSWORD_TYPE_MD5:
-			/* stored password already encrypted, only do salt */
-			if (!pg_md5_encrypt(shadow_pass + strlen("md5"),
-								md5_salt, md5_salt_len,
-								crypt_pwd))
-			{
-				return STATUS_ERROR;
-			}
-			break;
-
-		case PASSWORD_TYPE_PLAINTEXT:
-			/* stored password is plain, double-encrypt */
-			if (!pg_md5_encrypt(shadow_pass,
-								role,
-								strlen(role),
-								crypt_pwd2))
-			{
-				return STATUS_ERROR;
-			}
-			if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"),
-								md5_salt, md5_salt_len,
-								crypt_pwd))
-			{
-				return STATUS_ERROR;
-			}
-			break;
-
-		default:
-			/* unknown password hash format. */
-			*logdetail = psprintf(_("User \"%s\" has a password that cannot be used with MD5 authentication."),
-								  role);
-			return STATUS_ERROR;
+		return STATUS_ERROR;
 	}
 
 	if (strcmp(client_pass, crypt_pwd) == 0)
@@ -259,8 +213,8 @@ md5_crypt_verify(const char *role, const char *shadow_pass,
 /*
  * Check given password for given user, and return STATUS_OK or STATUS_ERROR.
  *
- * 'shadow_pass' is the user's correct password or password hash, as stored
- * in pg_authid.rolpassword.
+ * 'shadow_pass' is the user's correct password hash, as stored in
+ * pg_authid.rolpassword.
  * 'client_pass' is the password given by the remote user.
  *
  * In the error case, optionally store a palloc'd string at *logdetail
@@ -320,14 +274,10 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
 			break;
 
 		case PASSWORD_TYPE_PLAINTEXT:
-			if (strcmp(client_pass, shadow_pass) == 0)
-				return STATUS_OK;
-			else
-			{
-				*logdetail = psprintf(_("Password does not match for user \"%s\"."),
-									  role);
-				return STATUS_ERROR;
-			}
+			/*
+			 * We never store passwords in plaintext, so this shouldn't
+			 * happen.
+			 */
 			break;
 	}
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 818d2c29d4..2cad8b25b8 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -994,13 +994,21 @@ AlterOptRoleElem:
 				}
 			| ENCRYPTED PASSWORD Sconst
 				{
-					$$ = makeDefElem("encryptedPassword",
+					/*
+					 * These days, passwords are always stored in encrypted
+					 * form, so there is no difference between PASSWORD and
+					 * ENCRYPTED PASSWORD.
+					 */
+					$$ = makeDefElem("password",
 									 (Node *)makeString($3), @1);
 				}
 			| UNENCRYPTED PASSWORD Sconst
 				{
-					$$ = makeDefElem("unencryptedPassword",
-									 (Node *)makeString($3), @1);
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("UNENCRYPTED PASSWORD is no longer supported"),
+							 errhint("Remove UNENCRYPTED to store the password in encrypted form instead."),
+							 parser_errposition(@1)));
 				}
 			| INHERIT
 				{
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 587fbce147..cb4e621c84 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -405,20 +405,16 @@ static const struct config_enum_entry force_parallel_mode_options[] = {
 
 /*
  * password_encryption used to be a boolean, so accept all the likely
- * variants of "on" and "off", too.
+ * variants of "on", too. "off" used to store passwords in plaintext,
+ * but we don't support that anymore.
  */
 static const struct config_enum_entry password_encryption_options[] = {
-	{"plain", PASSWORD_TYPE_PLAINTEXT, false},
 	{"md5", PASSWORD_TYPE_MD5, false},
 	{"scram-sha-256", PASSWORD_TYPE_SCRAM_SHA_256, false},
-	{"off", PASSWORD_TYPE_PLAINTEXT, false},
-	{"on", PASSWORD_TYPE_MD5, false},
+	{"on", PASSWORD_TYPE_MD5, true},
 	{"true", PASSWORD_TYPE_MD5, true},
-	{"false", PASSWORD_TYPE_PLAINTEXT, true},
 	{"yes", PASSWORD_TYPE_MD5, true},
-	{"no", PASSWORD_TYPE_PLAINTEXT, true},
 	{"1", PASSWORD_TYPE_MD5, true},
-	{"0", PASSWORD_TYPE_PLAINTEXT, true},
 	{NULL, 0, false}
 };
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index e2a3351210..183fc37629 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1634,10 +1634,10 @@ psql_completion(const char *text, int start, int end)
 	{
 		static const char *const list_ALTERUSER[] =
 		{"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
-			"ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
+			"ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
 			"NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
 			"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
-			"REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
+			"REPLICATION", "RESET", "SET", "SUPERUSER",
 		"VALID UNTIL", "WITH", NULL};
 
 		COMPLETE_WITH_LIST(list_ALTERUSER);
@@ -1649,18 +1649,15 @@ psql_completion(const char *text, int start, int end)
 		/* Similar to the above, but don't complete "WITH" again. */
 		static const char *const list_ALTERUSER_WITH[] =
 		{"BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
-			"ENCRYPTED", "INHERIT", "LOGIN", "NOBYPASSRLS",
+			"ENCRYPTED PASSWORD", "INHERIT", "LOGIN", "NOBYPASSRLS",
 			"NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
 			"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD", "RENAME TO",
-			"REPLICATION", "RESET", "SET", "SUPERUSER", "UNENCRYPTED",
+			"REPLICATION", "RESET", "SET", "SUPERUSER",
 		"VALID UNTIL", NULL};
 
 		COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
 	}
 
-	/* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
-	else if (Matches4("ALTER", "USER|ROLE", MatchAny, "ENCRYPTED|UNENCRYPTED"))
-		COMPLETE_WITH_CONST("PASSWORD");
 	/* ALTER DEFAULT PRIVILEGES */
 	else if (Matches3("ALTER", "DEFAULT", "PRIVILEGES"))
 		COMPLETE_WITH_LIST2("FOR ROLE", "IN SCHEMA");
@@ -2502,10 +2499,10 @@ psql_completion(const char *text, int start, int end)
 	{
 		static const char *const list_CREATEROLE[] =
 		{"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
-			"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
+			"ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
 			"NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
 			"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
-			"REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
+			"REPLICATION", "ROLE", "SUPERUSER", "SYSID",
 		"VALID UNTIL", "WITH", NULL};
 
 		COMPLETE_WITH_LIST(list_CREATEROLE);
@@ -2517,21 +2514,15 @@ psql_completion(const char *text, int start, int end)
 		/* Similar to the above, but don't complete "WITH" again. */
 		static const char *const list_CREATEROLE_WITH[] =
 		{"ADMIN", "BYPASSRLS", "CONNECTION LIMIT", "CREATEDB", "CREATEROLE",
-			"ENCRYPTED", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
+			"ENCRYPTED PASSWORD", "IN", "INHERIT", "LOGIN", "NOBYPASSRLS",
 			"NOCREATEDB", "NOCREATEROLE", "NOINHERIT",
 			"NOLOGIN", "NOREPLICATION", "NOSUPERUSER", "PASSWORD",
-			"REPLICATION", "ROLE", "SUPERUSER", "SYSID", "UNENCRYPTED",
+			"REPLICATION", "ROLE", "SUPERUSER", "SYSID",
 		"VALID UNTIL", NULL};
 
 		COMPLETE_WITH_LIST(list_CREATEROLE_WITH);
 	}
 
-	/*
-	 * complete CREATE ROLE,USER,GROUP <name> ENCRYPTED,UNENCRYPTED with
-	 * PASSWORD
-	 */
-	else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "ENCRYPTED|UNENCRYPTED"))
-		COMPLETE_WITH_CONST("PASSWORD");
 	/* complete CREATE ROLE,USER,GROUP <name> IN with ROLE,GROUP */
 	else if (Matches4("CREATE", "ROLE|USER|GROUP", MatchAny, "IN"))
 		COMPLETE_WITH_LIST2("GROUP", "ROLE");
diff --git a/src/bin/scripts/createuser.c b/src/bin/scripts/createuser.c
index 35a53bf206..82a4d51498 100644
--- a/src/bin/scripts/createuser.c
+++ b/src/bin/scripts/createuser.c
@@ -48,7 +48,6 @@ main(int argc, char *argv[])
 		{"connection-limit", required_argument, NULL, 'c'},
 		{"pwprompt", no_argument, NULL, 'P'},
 		{"encrypted", no_argument, NULL, 'E'},
-		{"unencrypted", no_argument, NULL, 'N'},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -75,8 +74,7 @@ main(int argc, char *argv[])
 				createrole = TRI_DEFAULT,
 				inherit = TRI_DEFAULT,
 				login = TRI_DEFAULT,
-				replication = TRI_DEFAULT,
-				encrypted = TRI_DEFAULT;
+				replication = TRI_DEFAULT;
 
 	PQExpBufferData sql;
 
@@ -88,7 +86,7 @@ main(int argc, char *argv[])
 
 	handle_help_version_opts(argc, argv, "createuser", help);
 
-	while ((c = getopt_long(argc, argv, "h:p:U:g:wWedDsSaArRiIlLc:PEN",
+	while ((c = getopt_long(argc, argv, "h:p:U:g:wWedDsSaArRiIlLc:PE",
 							long_options, &optindex)) != -1)
 	{
 		switch (c)
@@ -153,10 +151,7 @@ main(int argc, char *argv[])
 				pwprompt = true;
 				break;
 			case 'E':
-				encrypted = TRI_YES;
-				break;
-			case 'N':
-				encrypted = TRI_NO;
+				/* no-op, accepted for backwards-compatibility */
 				break;
 			case 1:
 				replication = TRI_YES;
@@ -264,31 +259,22 @@ main(int argc, char *argv[])
 	printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
 	if (newpassword)
 	{
-		if (encrypted == TRI_YES)
-			appendPQExpBufferStr(&sql, " ENCRYPTED");
-		if (encrypted == TRI_NO)
-			appendPQExpBufferStr(&sql, " UNENCRYPTED");
+		char	   *encrypted_password;
+
 		appendPQExpBufferStr(&sql, " PASSWORD ");
 
-		if (encrypted != TRI_NO)
+		encrypted_password = PQencryptPasswordConn(conn,
+												   newpassword,
+												   newuser,
+												   NULL);
+		if (!encrypted_password)
 		{
-			char	   *encrypted_password;
-
-			encrypted_password = PQencryptPasswordConn(conn,
-													   newpassword,
-													   newuser,
-													   NULL);
-			if (!encrypted_password)
-			{
-				fprintf(stderr, _("%s: password encryption failed: %s"),
-						progname, PQerrorMessage(conn));
-				exit(1);
-			}
-			appendStringLiteralConn(&sql, encrypted_password, conn);
-			PQfreemem(encrypted_password);
+			fprintf(stderr, _("%s: password encryption failed: %s"),
+					progname, PQerrorMessage(conn));
+			exit(1);
 		}
-		else
-			appendStringLiteralConn(&sql, newpassword, conn);
+		appendStringLiteralConn(&sql, encrypted_password, conn);
+		PQfreemem(encrypted_password);
 	}
 	if (superuser == TRI_YES)
 		appendPQExpBufferStr(&sql, " SUPERUSER");
@@ -361,14 +347,12 @@ help(const char *progname)
 	printf(_("  -d, --createdb            role can create new databases\n"));
 	printf(_("  -D, --no-createdb         role cannot create databases (default)\n"));
 	printf(_("  -e, --echo                show the commands being sent to the server\n"));
-	printf(_("  -E, --encrypted           encrypt stored password\n"));
 	printf(_("  -g, --role=ROLE           new role will be a member of this role\n"));
 	printf(_("  -i, --inherit             role inherits privileges of roles it is a\n"
 			 "                            member of (default)\n"));
 	printf(_("  -I, --no-inherit          role does not inherit privileges\n"));
 	printf(_("  -l, --login               role can login (default)\n"));
 	printf(_("  -L, --no-login            role cannot login\n"));
-	printf(_("  -N, --unencrypted         do not encrypt stored password\n"));
 	printf(_("  -P, --pwprompt            assign a password to new role\n"));
 	printf(_("  -r, --createrole          role can create new roles\n"));
 	printf(_("  -R, --no-createrole       role cannot create roles (default)\n"));
diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h
index 63724f39ee..9bad67c890 100644
--- a/src/include/libpq/crypt.h
+++ b/src/include/libpq/crypt.h
@@ -16,10 +16,13 @@
 #include "datatype/timestamp.h"
 
 /*
- * Types of password hashes or verifiers that can be stored in
- * pg_authid.rolpassword.
+ * Types of password hashes or verifiers.
  *
- * This is also used for the password_encryption GUC.
+ * Plaintext passwords can be passed in by the user, in a CREATE/ALTER USER
+ * command. They will be encrypted to MD5 or SCRAM-SHA-256 format, before
+ * storing on-disk, so only MD5 and SCRAM-SHA-256 passwords should appear
+ * in pg_authid.rolpassword. They are also the allowed values for the
+ * password_encryption GUC.
  */
 typedef enum PasswordType
 {
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 54acd0f6bf..f4397afc64 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -1183,8 +1183,7 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
 	 * send the password in plaintext even if it was "off".
 	 */
 	if (strcmp(algorithm, "on") == 0 ||
-		strcmp(algorithm, "off") == 0 ||
-		strcmp(algorithm, "plain") == 0)
+		strcmp(algorithm, "off") == 0)
 		algorithm = "md5";
 
 	/*
diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl
index 216bdc031c..5a21ecd7e6 100644
--- a/src/test/authentication/t/001_password.pl
+++ b/src/test/authentication/t/001_password.pl
@@ -10,7 +10,7 @@ use strict;
 use warnings;
 use PostgresNode;
 use TestLib;
-use Test::More tests => 12;
+use Test::More tests => 8;
 
 # Delete pg_hba.conf from the given node, add a new entry to it
 # and then execute a reload to refresh it.
@@ -53,32 +53,26 @@ SKIP:
 	# password is used for all of them.
 	$node->safe_psql('postgres', "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';");
 	$node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';");
-	$node->safe_psql('postgres', "SET password_encryption='plain'; CREATE ROLE plain_role LOGIN PASSWORD 'pass';");
 	$ENV{"PGPASSWORD"} = 'pass';
 
 	# For "trust" method, all users should be able to connect.
 	reset_pg_hba($node, 'trust');
 	test_role($node, 'scram_role', 'trust', 0);
 	test_role($node, 'md5_role', 'trust', 0);
-	test_role($node, 'plain_role', 'trust', 0);
 
 	# For plain "password" method, all users should also be able to connect.
 	reset_pg_hba($node, 'password');
 	test_role($node, 'scram_role', 'password', 0);
 	test_role($node, 'md5_role', 'password', 0);
-	test_role($node, 'plain_role', 'password', 0);
 
-	# For "scram-sha-256" method, user "plain_role" and "scram_role" should
-	# be able to connect.
+	# For "scram-sha-256" method, user "scram_role" should be able to connect.
 	reset_pg_hba($node, 'scram-sha-256');
 	test_role($node, 'scram_role', 'scram-sha-256', 0);
 	test_role($node, 'md5_role', 'scram-sha-256', 2);
-	test_role($node, 'plain_role', 'scram-sha-256', 0);
 
 	# For "md5" method, all users should be able to connect (SCRAM
 	# authentication will be performed for the user with a scram verifier.)
 	reset_pg_hba($node, 'md5');
 	test_role($node, 'scram_role', 'md5', 0);
 	test_role($node, 'md5_role', 'md5', 0);
-	test_role($node, 'plain_role', 'md5', 0);
 }
diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out
index 9ec5a52bba..e768985455 100644
--- a/src/test/regress/expected/password.out
+++ b/src/test/regress/expected/password.out
@@ -4,21 +4,17 @@
 -- Tests for GUC password_encryption
 SET password_encryption = 'novalue'; -- error
 ERROR:  invalid value for parameter "password_encryption": "novalue"
-HINT:  Available values: plain, md5, scram-sha-256, off, on.
+HINT:  Available values: md5, scram-sha-256, on.
 SET password_encryption = true; -- ok
 SET password_encryption = 'md5'; -- ok
-SET password_encryption = 'plain'; -- ok
 SET password_encryption = 'scram-sha-256'; -- ok
 -- consistency of password entries
-SET password_encryption = 'plain';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
 SET password_encryption = 'md5';
 CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
 SET password_encryption = 'on';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4';
-SET password_encryption = 'plain';
 CREATE ROLE regress_passwd5 PASSWORD NULL;
 -- check list of created entries
 --
@@ -33,12 +29,11 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
     ORDER BY rolname, rolpassword;
      rolname     |                rolpassword_masked                 
 -----------------+---------------------------------------------------
- regress_passwd1 | role_pwd1
  regress_passwd2 | md54044304ba511dd062133eb5b4b84a2a3
  regress_passwd3 | md50e5699b6911d87f17a08b8d76a21e8b8
  regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd5 | 
-(5 rows)
+(4 rows)
 
 -- Rename a role
 ALTER ROLE regress_passwd3 RENAME TO regress_passwd3_new;
@@ -54,30 +49,32 @@ SELECT rolname, rolpassword
 (1 row)
 
 ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3;
--- ENCRYPTED and UNENCRYPTED passwords
-ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted
-ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5
+-- Change passwords with ALTER USER. With plaintext or already-encrypted
+-- passwords.
 SET password_encryption = 'md5';
-ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5
-ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo='; -- client-supplied SCRAM verifier, use as it is
+-- encrypt with MD5
+ALTER ROLE regress_passwd3 PASSWORD 'foo';
+-- already encrypted, use as they are
+ALTER ROLE regress_passwd2 PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb';
+ALTER ROLE regress_passwd4 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
 SET password_encryption = 'scram-sha-256';
-ALTER ROLE  regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier
-CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is
+-- create SCRAM verifier
+ALTER ROLE  regress_passwd5 PASSWORD 'foo';
+-- already encrypted with MD5, use as it is
+CREATE ROLE regress_passwd6 PASSWORD 'md53725413363ab045e20521bf36b8d8d7f';
 SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/]+==)\$([a-zA-Z0-9+/]+=):([a-zA-Z0-9+/]+=)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked
     FROM pg_authid
     WHERE rolname LIKE 'regress_passwd%'
     ORDER BY rolname, rolpassword;
      rolname     |                rolpassword_masked                 
 -----------------+---------------------------------------------------
- regress_passwd1 | foo
  regress_passwd2 | md5dfa155cadd5f4ad57860162f3fab9cdb
  regress_passwd3 | md5530de4c298af94b3b9f7d20305d2a1bf
  regress_passwd4 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd5 | SCRAM-SHA-256$4096:<salt>$<storedkey>:<serverkey>
  regress_passwd6 | md53725413363ab045e20521bf36b8d8d7f
-(6 rows)
+(5 rows)
 
-DROP ROLE regress_passwd1;
 DROP ROLE regress_passwd2;
 DROP ROLE regress_passwd3;
 DROP ROLE regress_passwd4;
diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql
index 1e022dbf2d..7efbc17b61 100644
--- a/src/test/regress/sql/password.sql
+++ b/src/test/regress/sql/password.sql
@@ -6,19 +6,15 @@
 SET password_encryption = 'novalue'; -- error
 SET password_encryption = true; -- ok
 SET password_encryption = 'md5'; -- ok
-SET password_encryption = 'plain'; -- ok
 SET password_encryption = 'scram-sha-256'; -- ok
 
 -- consistency of password entries
-SET password_encryption = 'plain';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
 SET password_encryption = 'md5';
 CREATE ROLE regress_passwd2 PASSWORD 'role_pwd2';
 SET password_encryption = 'on';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd4 PASSWORD 'role_pwd4';
-SET password_encryption = 'plain';
 CREATE ROLE regress_passwd5 PASSWORD NULL;
 
 -- check list of created entries
@@ -42,24 +38,27 @@ SELECT rolname, rolpassword
     ORDER BY rolname, rolpassword;
 ALTER ROLE regress_passwd3_new RENAME TO regress_passwd3;
 
--- ENCRYPTED and UNENCRYPTED passwords
-ALTER ROLE regress_passwd1 UNENCRYPTED PASSWORD 'foo'; -- unencrypted
-ALTER ROLE regress_passwd2 UNENCRYPTED PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb'; -- encrypted with MD5
+-- Change passwords with ALTER USER. With plaintext or already-encrypted
+-- passwords.
 SET password_encryption = 'md5';
-ALTER ROLE regress_passwd3 ENCRYPTED PASSWORD 'foo'; -- encrypted with MD5
 
-ALTER ROLE regress_passwd4 ENCRYPTED PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo='; -- client-supplied SCRAM verifier, use as it is
+-- encrypt with MD5
+ALTER ROLE regress_passwd3 PASSWORD 'foo';
+-- already encrypted, use as they are
+ALTER ROLE regress_passwd2 PASSWORD 'md5dfa155cadd5f4ad57860162f3fab9cdb';
+ALTER ROLE regress_passwd4 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
 
 SET password_encryption = 'scram-sha-256';
-ALTER ROLE  regress_passwd5 ENCRYPTED PASSWORD 'foo'; -- create SCRAM verifier
-CREATE ROLE regress_passwd6 ENCRYPTED PASSWORD 'md53725413363ab045e20521bf36b8d8d7f'; -- encrypted with MD5, use as it is
+-- create SCRAM verifier
+ALTER ROLE  regress_passwd5 PASSWORD 'foo';
+-- already encrypted with MD5, use as it is
+CREATE ROLE regress_passwd6 PASSWORD 'md53725413363ab045e20521bf36b8d8d7f';
 
 SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+/]+==)\$([a-zA-Z0-9+/]+=):([a-zA-Z0-9+/]+=)', '\1$\2:<salt>$<storedkey>:<serverkey>') as rolpassword_masked
     FROM pg_authid
     WHERE rolname LIKE 'regress_passwd%'
     ORDER BY rolname, rolpassword;
 
-DROP ROLE regress_passwd1;
 DROP ROLE regress_passwd2;
 DROP ROLE regress_passwd3;
 DROP ROLE regress_passwd4;
-- 
2.11.0

#12Albe Laurenz
laurenz.albe@wien.gv.at
In reply to: Tom Lane (#6)
Re: password_encryption, default and 'plain' support

Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Is it possible that there are still client libraries that don't support
password encryption at all? If so, are we willing to break them?
I'd say "yes" but it's worth thinking about.

We have one application that has been reduced to "password" authentication
ever since "crypt" authentication was removed, because they implemented the
line protocol rather than using libpq and never bothered to move to "md5".

But then, it might be a good idea to break this application, because that
would force the vendor to implement something that is not a
blatant security problem.

Yours,
Laurenz Albe

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Magnus Hagander
magnus@hagander.net
In reply to: Albe Laurenz (#12)
Re: password_encryption, default and 'plain' support

On Fri, May 5, 2017 at 9:38 AM, Albe Laurenz <laurenz.albe@wien.gv.at>
wrote:

Tom Lane wrote:

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, May 3, 2017 at 7:31 AM, Heikki Linnakangas <hlinnaka@iki.fi>

wrote:

So, I propose that we remove support for password_encryption='plain' in
PostgreSQL 10. If you try to do that, you'll get an error.

I have no idea how widely used that option is.

Is it possible that there are still client libraries that don't support
password encryption at all? If so, are we willing to break them?
I'd say "yes" but it's worth thinking about.

We have one application that has been reduced to "password" authentication
ever since "crypt" authentication was removed, because they implemented the
line protocol rather than using libpq and never bothered to move to "md5".

But then, it might be a good idea to break this application, because that
would force the vendor to implement something that is not a
blatant security problem.

It might. But I'm pretty sure the suggestion does not include removing the
"password" authentication type, that one will still exist. This is just
about password *storage*.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#14Michael Paquier
michael.paquier@gmail.com
In reply to: Heikki Linnakangas (#11)
Re: password_encryption, default and 'plain' support

On Thu, May 4, 2017 at 8:37 PM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 05/03/2017 08:40 PM, Tom Lane wrote:

The other question I can think to ask is what will happen during
pg_upgrade, given an existing installation with one or more passwords
stored plain. If the answer is "silently convert to MD5", I'd be
good with that.

Yes, it will silently convert to MD5. That happened even on earlier
versions, if you had password_encryption=on in the new cluster (which was
the default).

I'm planning to go ahead with the attached patch for this (removing
password_encryption='plain' support, but keeping the default as 'md5').

The patch attached does not apply on HEAD at 499ae5f, regression tests
are conflicting.

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English? It seems to me that this be non-plural,
as "for backward compatibility".

The comment at the top of check_password() in passwordcheck.c does not
mention scram, you may want to update that.

+                       /*
+                        * We never store passwords in plaintext, so
this shouldn't
+                        * happen.
+                        */
                        break;
An error here is overthinking?

-- consistency of password entries
-SET password_encryption = 'plain';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'md5';
Nit: this is skipping directly to role number 2.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Vik Fearing
vik.fearing@2ndquadrant.com
In reply to: Michael Paquier (#14)
Re: password_encryption, default and 'plain' support

On 05/05/2017 02:42 PM, Michael Paquier wrote:

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English?

No.

It seems to me that this be non-plural,
as "for backward compatibility".

"Backwards" is not plural, it's a regional variation of "backward" (or
vice versa depending on which region you come from). Both are correct.

--
Vik Fearing +33 6 46 75 15 36
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Gavin Flower
GavinFlower@archidevsys.co.nz
In reply to: Vik Fearing (#15)
Re: password_encryption, default and 'plain' support

On 06/05/17 22:44, Vik Fearing wrote:

On 05/05/2017 02:42 PM, Michael Paquier wrote:

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English?

No.

It seems to me that this be non-plural,
as "for backward compatibility".

"Backwards" is not plural, it's a regional variation of "backward" (or
vice versa depending on which region you come from). Both are correct.

I am English, born & bred, and 'Backwards' feels a lot more natural to me.

Cheers,
Gavin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Gavin Flower (#16)
Re: password_encryption, default and 'plain' support

On 05/06/2017 01:56 PM, Gavin Flower wrote:

On 06/05/17 22:44, Vik Fearing wrote:

On 05/05/2017 02:42 PM, Michael Paquier wrote:

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English?

No.

It seems to me that this be non-plural,
as "for backward compatibility".

"Backwards" is not plural, it's a regional variation of "backward" (or
vice versa depending on which region you come from). Both are correct.

I am English, born & bred, and 'Backwards' feels a lot more natural to me.

Another data point:

$ grep "backwards-comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
7
$ grep "backward-comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
3

Another important question is whether there should be a hyphen there or not?

$ grep "backward comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml |
wc -l
21
~/git-sandbox-pgsql/master (master)$ grep "backwards comp"
doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
11

It looks like the most popular spelling in our docs is "backward
compatibility". I'll go with that.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Michael Paquier (#14)
Re: password_encryption, default and 'plain' support

On 05/05/2017 03:42 PM, Michael Paquier wrote:

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English? It seems to me that this be non-plural,
as "for backward compatibility".

I changed most cases to "backward compatibility", except the one in
create_role.sgml, because there were other instances of "backwards
compatibility" on that page, and I didn't want this to stick out.

The comment at the top of check_password() in passwordcheck.c does not
mention scram, you may want to update that.

Reworded the comment, to not list all the possible values.

+                       /*
+                        * We never store passwords in plaintext, so
this shouldn't
+                        * happen.
+                        */
break;
An error here is overthinking?

It's not shown in the diff's context, but an error is returned just
after the switch statement. I considered leaving out the "case
PASSWORD_TYPE_PLAINTEXT" altogether, but then you might get compiler
warnings complaining that that enum value is not handled. I also
considered putting a an explicit "default:" there, which returns an
error, but then you'd again miss out on compiler warnings, if you add a
new password hash type and forget to add a case here to handle it.

-- consistency of password entries
-SET password_encryption = 'plain';
-CREATE ROLE regress_passwd1 PASSWORD 'role_pwd1';
SET password_encryption = 'md5';
Nit: this is skipping directly to role number 2.

Renumbered the test roles.

Committed with those little cleanups. Thanks for the review!

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Noname
ilmari@ilmari.org
In reply to: Heikki Linnakangas (#17)
Re: password_encryption, default and 'plain' support

Heikki Linnakangas <hlinnaka@iki.fi> writes:

On 05/06/2017 01:56 PM, Gavin Flower wrote:

On 06/05/17 22:44, Vik Fearing wrote:

On 05/05/2017 02:42 PM, Michael Paquier wrote:

+        This option is obsolete but still accepted for backwards
+        compatibility.
Isn't that incorrect English?

No.

It seems to me that this be non-plural,
as "for backward compatibility".

"Backwards" is not plural, it's a regional variation of "backward" (or
vice versa depending on which region you come from). Both are correct.

I am English, born & bred, and 'Backwards' feels a lot more natural to me.

Another data point:

$ grep "backwards-comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
7
$ grep "backward-comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
3

Another important question is whether there should be a hyphen there or not?

$ grep "backward comp" doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml |
wc -l
21
~/git-sandbox-pgsql/master (master)$ grep "backwards comp"
doc/src/sgml/ref/*.sgml doc/src/sgml/*.sgml | wc -l
11

This misses out instances where the phrase is broken across lines.
Using a less line-orented tool, ag (aka. The Silver Searcher), gives
more hits for the non-hyphenated case, but doesn't significantly change
the s-to-non-s ratio.

$ ag 'backwards-\s*comp' doc/**/*.sgml|grep -c backward
7
$ ag 'backward-\s*comp' doc/**/*.sgml|grep -c backward
3
$ ag 'backward\s+comp' doc/**/*.sgml | grep -c backward
29
* ag 'backwards\s+comp' doc/**/*.sgml | grep -c backward
20

--
"I use RMS as a guide in the same way that a boat captain would use
a lighthouse. It's good to know where it is, but you generally
don't want to find yourself in the same spot." - Tollef Fog Heen

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers