{"id":1696,"date":"2012-11-12T19:27:25","date_gmt":"2012-11-12T11:27:25","guid":{"rendered":"http:\/\/rmohan.com\/?p=1696"},"modified":"2012-11-12T19:27:25","modified_gmt":"2012-11-12T11:27:25","slug":"mysql-error-1045-access-denied-for-userlocalhost","status":"publish","type":"post","link":"https:\/\/mohan.sg\/?p=1696","title":{"rendered":"MySQL ERROR 1045 Access denied for &#8216;user&#8217;@&#8217;localhost&#8217;"},"content":{"rendered":"<p>The Problem<\/p>\n<p>The logfile of mysqld, \/var\/log\/upstart\/mysql.log,  reported yet another error: <\/p>\n<p>?120618 14:07:31 [Note] \/usr\/sbin\/mysqld: ready for connections.<\/p>\n<p>Version: &#8216;5.5.24-0ubuntu0.12.04.1&#8217;  socket: &#8216;\/var\/run\/mysqld\/mysqld.sock&#8217;  port: 3306  (Ubuntu)<\/p>\n<p>mysqld is alive<\/p>\n<p>Checking for tables which need an upgrade, are corrupt or were<\/p>\n<p>not closed cleanly.<\/p>\n<p>120618 14:07:36 [ERROR] Cannot find or open table nova\/projects from<\/p>\n<p>the internal data dictionary of InnoDB though the .frm file for the<\/p>\n<p>table exists. Maybe you have deleted and recreated InnoDB data<\/p>\n<p>This looked like a DB corruption. Assuming healing it will solve the problem I wasted a few hours on that, in vain. Finally it turned this is a harmless alert that has nothing to do with the Access Denied issue (but is probably a nova bug).<\/p>\n<p>Some posts on the subject suggested that the socket permissions prevented local access. In my installation:<\/p>\n<p># ll \/var\/run\/mysqld\/mysqld.sock<br \/>\nsrwxrwxrwx 1 mysql mysql 0 Jun 18 17:34 \/var\/run\/mysqld\/mysqld.sock<\/p>\n<p>Which is ok. <\/p>\n<p>Back to mysql&#8217;s user accounts.<\/p>\n<p>User &#8216;glance&#8217; was properly defined in mysql, as well as &#8216;keystone&#8217; and &#8216;nova&#8217;. Permissions and grants looked ok &#8211; and let&#8217;s recall openstack worked (!). Connecting from any remote host (same command as above, with &#8211;host of course) worked fine. The glance daemons glance-api and glance-registry  weren&#8217;t the only services imapcted by error 1045: keystone and nova had the same issue, and their respective log files (under \/var\/log\/upstart) had thousands of lines of the OperationalError quoted above (which is due to the fact openstack&#8217;s upstart jobs have a very &#8220;slim&#8221; logic).<\/p>\n<p>All that suggested that there was something special about &#8216;localhost&#8217; access to mysql. <\/p>\n<p>I use &#8216;etckeeper&#8217; to keep a log and trace of what&#8217;s getting installed and modified. Comparing log timestamps and git changes, I concluded that the mess was caused by a simple modification to \/etc\/hosts: the yellow line below, which is a step in the installation procedure, created the havoc:<\/p>\n<p>?127.0.0.1\tlocalhost<\/p>\n<p>127.0.1.1\tostk-controller1<\/p>\n<p>10.0.0.40 ostk-controller1<\/p>\n<p>10.0.0.41 ostk-nova1<\/p>\n<p>A Poor Workaround<\/p>\n<p>Putting this yellow line in comment provided a poor workaround: it solved mysql ERROR 1045, but the controller must have its hostname resolved in \/etc\/hosts so we&#8217;re not satisfied.<\/p>\n<p>Further reading suggested that the error has something to do with the way mysql interprets &#8216;%&#8217; in statements such as: <\/p>\n<p>GRANT USAGE ON *.* TO &#8216;glance&#8217;@&#8217;%&#8217; IDENTIFIED BY PASSWORD(&#8216;openstack&#8217;);<\/p>\n<p>Is it possible that &#8216;%&#8217; stands for &#8220;all hosts except localhost&#8221;? i read this more than once (see References below) but could hardly belive. Interestingly, the MySQL documentation isn&#8217;t clear about this question and that&#8217;s the reason, i guess, there&#8217;s so much confusion and so many posts related to ERROR 1045.<\/p>\n<p>It&#8217;s worth noting that the hint to the final answer was found in a post with the title &#8220;Any way to make anyhost &#8216;%&#8217; include localhost&#8221;&#8230;<\/p>\n<p>Understanding MySQL Access<\/p>\n<p>I&#8217;ve set up a separate VM to explore that, and here are my findings.<\/p>\n<p>After installing mysql-server (latest for Precise is 5.5.24), the USER table and GRANTS get the default settings listed below (for clarity i&#8217;ve cut the right side of the output so it doesn&#8217;t look exactly as on screen):<\/p>\n<p>[14:57:22]root@mysqltests[~]<br \/>\n# mysql -u root -p<br \/>\n. . .<br \/>\nServer version: 5.5.24-0ubuntu0.12.04.1 (Ubuntu)<br \/>\n. . .<\/p>\n<p>mysql> SELECT user,host,password FROM mysql.user;<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| user             | host       | password                |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| root             | localhost  | *77B48D6366D102139D3719 |<br \/>\n| root             | mysqltests | *77B48D6366D102139D3719 |<br \/>\n| root             | 127.0.0.1  | *77B48D6366D102139D3719 |<br \/>\n| root             | ::1        | *77B48D6366D102139D3719 |<br \/>\n|                  | localhost  |                         |<br \/>\n|                  | mysqltests |                         |<br \/>\n| debian-sys-maint | localhost  | *04D30B480932109EFD77E1 |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n7 rows in set (0.00 sec)<\/p>\n<p>mysql> show grants;<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br \/>\n| Grants for root@localhost                               |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br \/>\n| GRANT ALL PRIVILEGES ON *.* TO &#8216;root&#8217;@&#8217;localhost&#8217;       |<\/p>\n<p>|       IDENTIFIED BY PASSWORD &#8216;*77B48D6366D102139D3719&#8217;  |<\/p>\n<p>|       WITH GRANT OPTION                                 |<br \/>\n| GRANT PROXY ON &#8221;@&#8221; TO &#8216;root&#8217;@&#8217;localhost&#8217; WITH GRANT   |<\/p>\n<p>|                                       OPTION            |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+<br \/>\n2 rows in set (0.00 sec)<\/p>\n<p>The mysql.user Table<\/p>\n<p>At first glance, we have 2 users (root and debian-sys-maint). That&#8217;s wrong, because mysql&#8217;s &#8220;user&#8221; is a &#8216;user&#8217;@&#8217;host&#8217; pair association. So we have 7 in total: &#8216;root&#8217; is defined (with the same password) for any combination of &#8216;localhost&#8217; (the first 4 lines), then we have 2 strange lines with empty username, and finally the debian backdoor &#8216;debian-sys-maint&#8217;. <\/p>\n<p>The grants<\/p>\n<p>The &#8216;show grants&#8217; above shows only grants for &#8216;root&#8217;. But if we run the next staement, we see what access is provided to any user connecting from &#8216;localhost&#8217;:<\/p>\n<p>mysql> show grants for &#8221;@&#8217;localhost&#8217;;<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br \/>\n| Grants for @localhost                |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<br \/>\n| GRANT USAGE ON *.* TO &#8221;@&#8217;localhost&#8217; |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+<\/p>\n<p>Which (indirectly) explains why running this command (as Linux user &#8216;ori&#8217;) doesn&#8217;t require a password: <\/p>\n<p>[16:16:57]ori@mysqltests[~]<\/p>\n<p>$ mysqladmin ping<br \/>\nmysqld is alive<\/p>\n<p>Where this one fails:<\/p>\n<p>[16:14:59]ori@mysqltests[~]<br \/>\n$ mysqladmin -uroot ping<br \/>\nmysqladmin: connect to server at &#8216;localhost&#8217; failed<br \/>\nerror: &#8216;Access denied for user &#8216;root&#8217;@&#8217;localhost&#8217; (using password: NO)&#8217;<\/p>\n<p>Honestly, in the beginning i thought there&#8217;s some balck magic here related to the user (&#8216;ori&#8217;, in this case) defined during ubuntu installation, or a special Linux group memebership, or some apparmor profile or god-knows what else. <\/p>\n<p>But there&#8217;s no black magic after all, and it&#8217;s all inside mysql:<\/p>\n<p>The first thing to bear in mind is that the empty USER field &#8221; is a wildcard, same as &#8216;%&#8217; for host. <\/p>\n<p>The second is that mysql prefers the explicit match over the wildcard. For example, user &#8216;root&#8217; can match either [1] the explicit &#8216;root&#8217;@localhost&#8217; row or [2] the wildcard &#8221;@&#8217;localhost&#8217; row. Since there&#8217;s an explicit entry for [1] in the table mysql.user, it&#8217;ll be used. This in turn requires a password so when i try to connect as &#8216;root&#8217; without a password i&#8217;m rejected.<\/p>\n<p>When i connect as &#8216;ori&#8217; &#8211; which isn&#8217;t even a mysql user, there&#8217;s only one possible match &#8211; &#8221;@&#8217;localhost&#8217; and this line in the table doesn&#8217;t have a password.<\/p>\n<p>This nicely explains why the above mysqladmin command works for &#8216;ori&#8217; and fails for &#8216;root&#8217;. <\/p>\n<p>To sum it up: mysql controls access (or connection request) based on the USER table. Which user, from which host and whether a password is required. <\/p>\n<p>Once connected, the GRANTS determine what the user is allowed to do. When connected as &#8216;ori&#8217; i&#8217;m limited to &#8220;USAGE&#8221; (e.g. check if server is up, what version and the like of inoffensive commands). <\/p>\n<p>So far so good &#8211; but why &#8216;glance&#8217;@&#8217;localhost&#8217; is denied access on the OpenStack controller?<\/p>\n<p>When the static IP address of the conroller wasn&#8217;t in \/etc\/hosts (or after it was commented-out), there was only one match for &#8216;glance&#8217; = &#8216;glance&#8217;@&#8217;%&#8217;<\/p>\n<p>This, in turn, comes from the connection string (in \/etc\/glance\/glance-registry.conf) which is:<\/p>\n<p>sql_connection = mysql:\/\/glance:openstack@10.0.0.40\/glance<\/p>\n<p>It specifies user, password and host.<\/p>\n<p>The line I&#8217;ve added for 10.0.0.40 in \/etc\/hosts, told mysql (indirectly) that host &#8216;ostk-controller1&#8217; is actually &#8216;localhsot&#8217;. From now on, there are 2 possible matches for &#8216;glance&#8217;, and the one picked by mysql is &#8221;@&#8217;localhost&#8217;. This row, however, doesn&#8217;t require a password &#8211; which the sql_connection string provide.<\/p>\n<p>And that&#8217;s why all OpenStack services couldn&#8217;t connect to mysql.<\/p>\n<p>Check against the USER table below, this was taken from ostk-controller (not the test VM):<\/p>\n<p>mysql> SELECT user,host,password FROM mysql.user;<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| user             | host             | password                |<\/p>\n<p>+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| root             | localhost        | *3A4A03AC22526F6B591010 |<\/p>\n<p>| root             | ostk-controller1 | *3A4A03AC22526F6B591010 |<\/p>\n<p>| root             | 127.0.0.1        | *3A4A03AC22526F6B591010 |<\/p>\n<p>| root             | ::1              | *3A4A03AC22526F6B591010 |<br \/>\n|                  | localhost        |                         |<\/p>\n<p>|                  | ostk-controller1 |                         |<br \/>\n| debian-sys-maint | localhost        | *F714636CE8A7836873F7C8 |<br \/>\n| nova             | %                | *3A4A03AC22526F6B591010 |<br \/>\n| glance           | %                | *3A4A03AC22526F6B591010 |<br \/>\n| keystone         | %                | *3A4A03AC22526F6B591010 |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n10 rows in set (0.00 sec)<\/p>\n<p>Solution for ERROR 1045<\/p>\n<p>After understanding why, let&#8217;s improve on the poor workaround.<\/p>\n<p>I&#8217;d like to credit an answer by Paul DuBois from 2004 for this solution(it&#8217;s worth noting that the subject was &#8220;Re: Any way to make anyhost &#8216;%&#8217; include localhost&#8221;).<\/p>\n<p>Borrowing from there, here&#8217;s the remedy:<\/p>\n<p>in MySQL:<\/p>\n<p>mysql -uroot -p<\/p>\n<p>DELETE FROM mysql.user WHERE Host=&#8217;localhost&#8217; AND User=&#8221;;<\/p>\n<p>DELETE FROM mysql.user WHERE Host=&#8217;ostk-controller1&#8242; AND User=&#8221;;<\/p>\n<p>FLUSH PRIVILEGES;<\/p>\n<p>in \/etc\/hosts:<\/p>\n<p>Replace the line<\/p>\n<p>127.0.1.1   ostk-controller1<\/p>\n<p>by this one:<\/p>\n<p>10.0.0.40  ostk-controller1<\/p>\n<p>Quoting from Debian&#8217;s reference manual:<\/p>\n<p>For a system with a permanent IP address, that permanent IP address should be used here instead of 127.0.1.1<\/p>\n<p>finally restart networking and mysqld &#8211; or simply reboot.<\/p>\n<p>A Second Solution<\/p>\n<p>Months after going through the above study, i found out why some OpenStack installations don&#8217;t hit this issue; The keystone installation instructions (from Ubuntu, for Essex, can be found here) create each OSTK user in mysql twice, as in: <\/p>\n<p>mysql> CREATE DATABASE keystone;<br \/>\nCREATE USER \u2018keystone\u2019@\u2019localhost\u2019 IDENTIFIED BY \u2018Secret_pass\u2019;<br \/>\nGRANT ALL PRIVILEGES ON keystone.* TO &#8216;keystone\u2019@\u2019localhost\u2019<br \/>\nWITH GRANT OPTION;<br \/>\nCREATE USER \u2018keystone\u2019@\u2019%\u2019 IDENTIFIED BY \u2018Secret_pass\u2019;<br \/>\nGRANT ALL PRIVILEGES ON keystone.* TO \u2018keystone\u2019@\u2019%\u2019<br \/>\nIDENTIFIED BY \u2018Secret_pass\u2019;<br \/>\nFLUSH PRIVILEGES;<\/p>\n<p>mysql -u root -p <\/p>\n<p>CREATE USER &#8216;bill&#8217;@&#8217;%&#8217; IDENTIFIED BY &#8216;passpass&#8217;;<\/p>\n<p>grant all privileges on *.* to &#8216;bill&#8217;@&#8217;%&#8217; with grant option;<\/p>\n<p>mysql -u bill -p<\/p>\n<p>ERROR 1045 (28000): Access denied for user &#8216;bill&#8217;@&#8217;localhost&#8217; (using password: YES)<\/p>\n<p>CREATE USER bill@localhost IDENTIFIED BY &#8216;passpass&#8217;;<br \/>\ngrant all privileges on *.* to bill@localhost with grant option;<\/p>\n<p>If you want to connect remotely, you must specify either the DNS name, the public IP, or 127.0.0.1 using TCP\/IP:<\/p>\n<p>mysql -u bill -p -hmydb@mydomain.com<br \/>\nmysql -u bill -p -h10.1.2.30<br \/>\nmysql -u bill -p -h127.0.0.1 &#8211;protocol=TCP<\/p>\n<p>SELECT USER(),CURRENT_USER();<\/p>\n<p>mysql> select user,host from mysql.user;<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| user    | host      |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| lwdba   | %         |<br \/>\n| mywife  | %         |<br \/>\n| lwdba   | 127.0.0.1 |<br \/>\n| root    | 127.0.0.1 |<br \/>\n| lwdba   | localhost |<br \/>\n| root    | localhost |<br \/>\n| vanilla | localhost |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n7 rows in set (0.00 sec)<\/p>\n<p>mysql> grant all on *.* to x@&#8217;%&#8217;;<br \/>\nQuery OK, 0 rows affected (0.02 sec)<\/p>\n<p>mysql> select user,host from mysql.user;<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| user    | host      |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| lwdba   | %         |<br \/>\n| mywife  | %         |<br \/>\n| x       | %         |<br \/>\n| lwdba   | 127.0.0.1 |<br \/>\n| root    | 127.0.0.1 |<br \/>\n| lwdba   | localhost |<br \/>\n| root    | localhost |<br \/>\n| vanilla | localhost |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n8 rows in set (0.00 sec)<\/p>\n<p>mysql> update mysql.user set user=&#8221; where user=&#8217;x&#8217;;<br \/>\nQuery OK, 1 row affected (0.00 sec)<br \/>\nRows matched: 1  Changed: 1  Warnings: 0<\/p>\n<p>mysql> flush privileges;<br \/>\nQuery OK, 0 rows affected (0.01 sec)<\/p>\n<p>mysql> select user,host from mysql.user;<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| user    | host      |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n|         | %         |<br \/>\n| lwdba   | %         |<br \/>\n| mywife  | %         |<br \/>\n| lwdba   | 127.0.0.1 |<br \/>\n| root    | 127.0.0.1 |<br \/>\n| lwdba   | localhost |<br \/>\n| root    | localhost |<br \/>\n| vanilla | localhost |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n8 rows in set (0.00 sec)<\/p>\n<p>mysql><\/p>\n<p>~$ mysql -u root -p<br \/>\nEnter Password:<\/p>\n<p>mysql> grant all privileges on *.* to bill@localhost identified by &#8216;pass&#8217; with grant option;<\/p>\n<p>root@myhost:\/home\/mysql-5.5.16-linux2.6-x86_64# .\/mysql -ubill -ppass &#8211;socket=\/tmp\/mysql-5.5.sock<br \/>\nWelcome to the MySQL monitor.  Commands end with ; or \\g.<br \/>\nYour MySQL connection id is 7<br \/>\nServer version: 5.5.16 MySQL Community Server (GPL)<\/p>\n<p>Type &#8216;help;&#8217; or &#8216;\\h&#8217; for help. Type &#8216;\\c&#8217; to clear the buffer.<\/p>\n<p>mysql> SELECT user, host FROM mysql.user;<br \/>\n+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| user | host      |<br \/>\n+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n| bill | %         |<br \/>\n| root | 127.0.0.1 |<br \/>\n| root | ::1       |<br \/>\n| root | localhost |<br \/>\n+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8211;+<br \/>\n4 rows in set (0.00 sec)<\/p>\n<p>mysql> SELECT USER(), CURRENT_USER();<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| USER()         | CURRENT_USER() |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n| bill@localhost | bill@%         |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;-+<br \/>\n1 row in set (0.02 sec)<\/p>\n<p>mysql> SHOW VARIABLES LIKE &#8216;skip_networking&#8217;;<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;-+<br \/>\n| Variable_name   | Value |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;-+<br \/>\n| skip_networking | ON    |<br \/>\n+&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;-+<br \/>\n1 row in set (0.00 sec)<\/p>\n<p>mysql><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Problem<\/p>\n<p>The logfile of mysqld, \/var\/log\/upstart\/mysql.log, reported yet another error: <\/p>\n<p>?120618 14:07:31 [Note] \/usr\/sbin\/mysqld: ready for connections.<\/p>\n<p>Version: &#8216;5.5.24-0ubuntu0.12.04.1&#8217; socket: &#8216;\/var\/run\/mysqld\/mysqld.sock&#8217; port: 3306 (Ubuntu)<\/p>\n<p>mysqld is alive<\/p>\n<p>Checking for tables which need an upgrade, are corrupt or were<\/p>\n<p>not closed cleanly.<\/p>\n<p>120618 14:07:36 [ERROR] Cannot find or open table nova\/projects from<\/p>\n<p>the internal [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1696"}],"collection":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1696"}],"version-history":[{"count":1,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1696\/revisions"}],"predecessor-version":[{"id":1698,"href":"https:\/\/mohan.sg\/index.php?rest_route=\/wp\/v2\/posts\/1696\/revisions\/1698"}],"wp:attachment":[{"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1696"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1696"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mohan.sg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}