<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Florian Köhler</title>
    <description>The latest articles on DEV Community by Florian Köhler (@flokoe).</description>
    <link>https://dev.to/flokoe</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F444899%2Ffac671f8-862e-4b79-bd38-ac8c2edba49c.jpg</url>
      <title>DEV Community: Florian Köhler</title>
      <link>https://dev.to/flokoe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/flokoe"/>
    <language>en</language>
    <item>
      <title>MySQL/MariaDB character sets and collations explained – why utf8 is not UTF-8</title>
      <dc:creator>Florian Köhler</dc:creator>
      <pubDate>Tue, 04 Jan 2022 12:04:32 +0000</pubDate>
      <link>https://dev.to/flokoe/database-character-sets-and-collations-explained-why-utf8-is-not-utf-8-3h7b</link>
      <guid>https://dev.to/flokoe/database-character-sets-and-collations-explained-why-utf8-is-not-utf-8-3h7b</guid>
      <description>&lt;p&gt;
  Table Of Contents
  &lt;ul&gt;
&lt;li&gt;Character sets and collations explained&lt;/li&gt;
&lt;li&gt;Charater sets: The tale of □�💩&lt;/li&gt;
&lt;li&gt;Why &lt;code&gt;utf8&lt;/code&gt; in MySQL is not UTF-8&lt;/li&gt;
&lt;li&gt;Collations: How to sort things&lt;/li&gt;
&lt;li&gt;What about performance?&lt;/li&gt;
&lt;li&gt;
Conclusion
&lt;/li&gt;
&lt;/ul&gt;




&lt;/p&gt;
&lt;p&gt;The relationship between character sets and collations always seemed pretty vague to me, let alone the possible impact on performance. So if you are like me and want to know the difference between &lt;code&gt;utf8&lt;/code&gt; and &lt;code&gt;utf8mb4&lt;/code&gt; and why mixed collations are bad for your database performance, read on!&lt;/p&gt;
&lt;h2&gt;
  
  
  Character sets and collations explained
&lt;/h2&gt;

&lt;p&gt;Since computers only understand binary and humans don't, we use character sets to map binary to specific characters. The difficulty was that different nations used different symbols and sometimes mapped the same binary sequence to other characters. So based on the character set you used, the same data could mean different things.&lt;/p&gt;

&lt;p&gt;Furthermore, depending on your language, you may sort certain characters differently than in other languages.&lt;/p&gt;

&lt;p&gt;To quote the MariaDB documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A character set is a set of characters [and its mapping to binary] while a collation is the rules for comparing and sorting a particular character set.&lt;br&gt;&lt;br&gt;
– &lt;a href="https://mariadb.com/kb/en/character-set-and-collation-overview/"&gt;MariaDB: Character Set and Collation Overview&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, the first character of this article, &lt;code&gt;T&lt;/code&gt; (LATIN CAPITAL LETTER T), in binary looks like &lt;code&gt;1010100&lt;/code&gt;. The computer reads this binary sequence and knows that this is 84 in decimal. Now it looks up which character maps to this number. Using the UTF-8 character set, the number 84 equals &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Charater sets: The tale of □�💩
&lt;/h2&gt;

&lt;p&gt;One of the most known character sets is ASCII (American Standard Code for Information Interchange). It only supports 128 different characters and is nowadays primarily used for art 😉&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   |           |
       |      |  |
  | |   |       |
      ___     _%%%_
  \,-' '_|    \___/    hjm
  /""----'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sperm whale and a bowl of petunias above the surface of an alien planet by Harry Mason (Hajoma).&lt;/p&gt;

&lt;p&gt;Someone even recreated the &lt;a href="https://www.asciimation.co.nz"&gt;entire fourth episode of Star Wars in ASCII&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even though 128 characters are enough to cover the English language and a few basic symbols, the limited range is unsuitable for international and modern communication. Therefore the UTF-8 standard was created, which is 100% backward compatible with ASCII but allows up to four bytes per character instead of just one.&lt;/p&gt;

&lt;p&gt;Four bytes enable pretty much every character of every language, and that is why we can use all these funny emojis and don't see something like □�. Over time it became the de facto standard for everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;utf8&lt;/code&gt; in MySQL is not UTF-8
&lt;/h2&gt;

&lt;p&gt;Of course, such an extensive and versatile character set is handy for a database that may store very different and complex data. That is why MySQL already implemented the standard for UTF-8 (&lt;a href="https://www.ietf.org/rfc/rfc2279.txt"&gt;RFC 2279&lt;/a&gt;) in the &lt;a href="https://github.com/mysql/mysql-server/commit/55e0a9cb01af4b01bc4e4395de9e4dd2a1b0cf23"&gt;pre-pre-release of MySQL 4.1 on March 28, 2002&lt;/a&gt;. The old standard even allowed for six bytes per character.&lt;/p&gt;

&lt;p&gt;For whatever reason, a few months later, in September 2002, a MySQL developer decided to push a one-byte commit &lt;a href="https://github.com/mysql/mysql-server/commit/43a506c0ced0e6ea101d3ab8b4b423ce3fa327d0"&gt;UTF8 now works with up to 3 byte sequences only&lt;/a&gt; to the repository and change the allowed bytes from six to three.&lt;/p&gt;

&lt;p&gt;Since then, the character set called &lt;code&gt;utf8&lt;/code&gt; has been a crippled and proprietary variation as it neither conforms to the old nor the new definition (&lt;a href="https://datatracker.ietf.org/doc/html/rfc3629"&gt;RFC 3629&lt;/a&gt;) of UTF-8. The misleading name still causes issues today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is probably one of most expensive single char commits in world...&lt;br&gt;&lt;br&gt;
– morphles, Nov 25, 2021&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because the &lt;code&gt;utf8&lt;/code&gt; character set only allows 3 bytes, you can't store some special characters in a database that utilizes this character set. Unfortunately, no one knows who made the change as all names were lost when moving the repository from BitKeeper to GitHub.&lt;/p&gt;

&lt;p&gt;To remediate this mistake &lt;a href="https://web.archive.org/web/20190201033750/https://dev.mysql.com/doc/relnotes/mysql/5.5/en/news-5-5-3.html"&gt;MySQL added the &lt;code&gt;utf8mb4&lt;/code&gt; charset in version 5.5.3&lt;/a&gt;. &lt;code&gt;utf8mb4&lt;/code&gt; fully implements the current standard. Now &lt;code&gt;utf8&lt;/code&gt; is an alias for &lt;code&gt;utf8mb3&lt;/code&gt; and will be switched to &lt;code&gt;utf8mb4&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collations: How to sort things
&lt;/h2&gt;

&lt;p&gt;The order of numbers is pretty straightforward – four is lower and comes before the number five. Even the English alphabet is still pretty easy. But what about other languages with additional characters or completely different symbols? Which emoji comes first? 😃 (SMILING FACE WITH OPEN MOUTH) or 😋 (FACE SAVOURING DELICIOUS FOOD)?&lt;/p&gt;

&lt;p&gt;Collations – sets of algorithms – determine how to sort certain characters. Which collation works best for you depends on your use case. But first, let's see how we can determine the difference between each collation.&lt;/p&gt;

&lt;p&gt;To get a list of all collations your server supports, we can execute the following (shorted view):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;MariaDB&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;COLLATION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;------------------------------+----------+------+---------+----------+---------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;Collation&lt;/span&gt;                    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Charset&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;Default&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Compiled&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Sortlen&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;------------------------------+----------+------+---------+----------+---------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;           &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt;     &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt;      &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_bin&lt;/span&gt;                  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="mi"&gt;46&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;         &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt;      &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_ci&lt;/span&gt;           &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;utf8mb4&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="mi"&gt;224&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;         &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Yes&lt;/span&gt;      &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;------------------------------+----------+------+---------+----------+---------+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The collation name is separated into three parts. The first part is always the character set the collation belongs to. A collation can only be associated with one character set, but there can be multiple collations for a character set. The second part always describes the functionality of the collation. And the optional third part can be one or more additional feature flags.&lt;/p&gt;

&lt;p&gt;Here is a list of common feature flags:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suffix&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;case-insensitive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;case-sensitive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The middle part is the most interesting because it specifies the collation algorithm.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bin&lt;/code&gt; stands for &lt;code&gt;binary&lt;/code&gt; and sorts data by its binary notation and does not consider any language-specific rules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;general&lt;/code&gt; honors some rules but uses a simplified algorithm favoring speed over accuracy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;unicode&lt;/code&gt; or its versioned variants like &lt;code&gt;unicode_520&lt;/code&gt; use the official UCS (Universal Coded Character Set) algorithms. Unicode collations provide the most accurate sorting.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;utf8mb4_general_ci&lt;/code&gt; does not knwo how to sort &lt;code&gt;s&lt;/code&gt; and the German character &lt;code&gt;ß&lt;/code&gt; ("sharp S") in contrast to &lt;code&gt;utf8mb4_unicode_520_ci&lt;/code&gt; which sorts &lt;code&gt;ß&lt;/code&gt; just fine (&lt;code&gt;ß&lt;/code&gt; comes after &lt;code&gt;s&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;MariaDB&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;                                     &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MariaDB&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;                                     &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;---------------------------------------+&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MariaDB&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_520_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_520_ci&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;                                         &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;001&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;MariaDB&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_520_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s1"&gt;'s'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'ß'&lt;/span&gt; &lt;span class="k"&gt;COLLATE&lt;/span&gt; &lt;span class="n"&gt;utf8mb4_unicode_520_ci&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;                                         &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="c1"&gt;-------------------------------------------+&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, &lt;code&gt;utf8mb4_unicode_ci&lt;/code&gt; is based on UCS 4.0, which is very old. Even the newer &lt;code&gt;utf8mb4_unicode_520_ci&lt;/code&gt; (UCS 5.2.0) is more than ten years old. But newer collations are already discussed, and we may see collations based on UCS 14 in version 10.8 of MariaDB. MySQL already implemented a few collations based on more recent UCS versions.&lt;/p&gt;

&lt;p&gt;There are language-specific variants like &lt;code&gt;utf8mb4_german2_ci&lt;/code&gt;, but I have never used them personally. I recommend sticking to the &lt;code&gt;unicode&lt;/code&gt; versions as they fit most use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about performance?
&lt;/h2&gt;

&lt;p&gt;There are some considerations when choosing your collation. The most important one is always to use the same collation when comparing strings.&lt;/p&gt;

&lt;p&gt;For example, when joining two tables with different sorting rulesets, MariaDB/MySQL cannot use indices and falls back scanning the entire tables.&lt;/p&gt;

&lt;p&gt;Regarding the different collation algorithms: The &lt;code&gt;unicode&lt;/code&gt; variants should be slower than the &lt;code&gt;general&lt;/code&gt; variant due to the more complex algorithms, but this was years ago when computers were much weaker than now. With modern hardware, the speed gain should be hardly notable.&lt;/p&gt;

&lt;p&gt;One last concern is the size stored on the disk because UTF-8 supports four bytes per character. But since UTF-8 is a variable-width character encoding, it only uses as many bytes as needed. For example, the first 128 characters like ASCII only use one byte.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now you know the difference between &lt;code&gt;utf8&lt;/code&gt; and &lt;code&gt;utf8mb4&lt;/code&gt; and what collation to use. There is no reason to use &lt;code&gt;utf8/utf8mb3&lt;/code&gt;, and I believe everyone who chose &lt;code&gt;utf8&lt;/code&gt; expected to get the real UTF-8 (&lt;code&gt;utf8mb4&lt;/code&gt;), not a crippled version. So to use it, you have to specify &lt;code&gt;utf8mb4&lt;/code&gt; explicitly.&lt;/p&gt;

&lt;p&gt;Furthermore, we should prefer accuracy over speed. There is no need to use an old and quirky collation like &lt;code&gt;utf8mb4_general_ci&lt;/code&gt; with modern hardware.&lt;/p&gt;

&lt;p&gt;If you ask yourself how to convert your database stay tuned and follow me. I will cover this topic in my next post. Until then, have fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Did I add value?
&lt;/h2&gt;

&lt;p&gt;I don't like ads, and I respect your privacy. Therefore my blog has no advertisements or any tracking cookies.&lt;/p&gt;

&lt;p&gt;If you like what you read, please support my work: &lt;a href="https://www.flokoe.de/buymeabeer/"&gt;Buy me a beer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you can't make monetary support, I understand. Please like and share this content on the platform of your choice.&lt;/p&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>devops</category>
      <category>mysql</category>
    </item>
    <item>
      <title>How To Fix Slow MariaDB Replication Lag</title>
      <dc:creator>Florian Köhler</dc:creator>
      <pubDate>Wed, 29 Sep 2021 13:19:52 +0000</pubDate>
      <link>https://dev.to/flokoe/fix-slow-mariadb-replication-lag-f07</link>
      <guid>https://dev.to/flokoe/fix-slow-mariadb-replication-lag-f07</guid>
      <description>&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;If you have experienced significant replication lags and replication so slow that it needed hours to complete or couldn't catch up at all, I may have a solution for you.&lt;/p&gt;

&lt;p&gt;A couple of weeks ago, I set up a MariaDB replication from scratch for a production database. The database has a considerable size and is under heavy use.&lt;/p&gt;

&lt;p&gt;As usual, I used &lt;a href="https://mariadb.com/kb/en/mariabackup/"&gt;Mariabackup&lt;/a&gt; to copy the entire data directory of MariaDB to the new replica server. Unfortunately, I had to interrupt my work and wasn't able to continue until 12 hours later. As I resumed where I left off, I noticed that the database grew substantially. Since I didn't want to resync about 200 GB of data, I left the rest to the replication.&lt;/p&gt;

&lt;p&gt;Well, It did not go as planned. The replication was so slow that it couldn't catch up.&lt;/p&gt;

&lt;p&gt;The server had enough resources to handle the amount of data, so why was it so slow? After some research, I found that while &lt;strong&gt;MariaDB fully benefits from multiple CPU cores, the replication process does not!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The replication process only runs on one core and processes events in serial. Luckily, you can fix this by increasing &lt;a href="https://mariadb.com/kb/en/replication-and-binary-log-system-variables/#slave_parallel_threads"&gt;slave_parallel_threads&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On your replica server, set the value to the number of CPU cores you can spare. You can change this parameter without restarting the database, but to do this, you first have to stop the replication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;STOP&lt;/span&gt; &lt;span class="n"&gt;SLAVE&lt;/span&gt; &lt;span class="n"&gt;SQL_THREAD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;slave_parallel_threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;START&lt;/span&gt; &lt;span class="n"&gt;SLAVE&lt;/span&gt; &lt;span class="n"&gt;SQL_THREAD&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;GLOBAL&lt;/span&gt; &lt;span class="n"&gt;VARIABLES&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'slave_parallel_threads'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your replica server will execute events in parallel (shortened view):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MariaDB [mysql]&amp;gt; SHOW PROCESSLIST;
+--------------+-----------------------------------------------------------------------------+
| Command      | State                                                                       |
+--------------+-----------------------------------------------------------------------------+
| Slave_IO     | Waiting for master to send event                                            |
| Slave_worker | Waiting for work from SQL thread                                            |
| Slave_worker | Waiting for prior transaction to commit                                     |
| Slave_worker | Closing tables                                                              |
| Slave_worker | Waiting for work from SQL thread                                            |
| Slave_SQL    | Slave has read all relay log; waiting for the slave I/O thread to update it |
+--------------+-----------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this is helpful to anyone who has similar issues.&lt;/p&gt;

</description>
      <category>database</category>
      <category>sql</category>
      <category>devops</category>
      <category>performance</category>
    </item>
    <item>
      <title>How Access Control Lists (ACLs) work and how to use them</title>
      <dc:creator>Florian Köhler</dc:creator>
      <pubDate>Thu, 23 Sep 2021 11:05:02 +0000</pubDate>
      <link>https://dev.to/flokoe/mastering-access-control-lists-acls-once-and-for-all-3geb</link>
      <guid>https://dev.to/flokoe/mastering-access-control-lists-acls-once-and-for-all-3geb</guid>
      <description>&lt;p&gt;
  Table Of Contents
  &lt;ul&gt;
&lt;li&gt;Requirements&lt;/li&gt;
&lt;li&gt;What exactly are ACLs&lt;/li&gt;
&lt;li&gt;Recap the Basics&lt;/li&gt;
&lt;li&gt;Viewing current ACLs&lt;/li&gt;
&lt;li&gt;
How ACLs work

&lt;ul&gt;
&lt;li&gt;Masks and effective rights explained&lt;/li&gt;
&lt;li&gt;Precedence of ACLs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Working with ACL entries

&lt;ul&gt;
&lt;li&gt;How to create/modify ACL entries&lt;/li&gt;
&lt;li&gt;Creating default permissions for new files&lt;/li&gt;
&lt;li&gt;Removing ACL entries&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Conclusion
&lt;/li&gt;
&lt;/ul&gt;




&lt;/p&gt;
&lt;p&gt;I often use ACLs when I have to give permissions to specific users or groups without compromising security. But I never fully understood how they work, as they are pretty complex. This guide will explain how they work and how to use them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;I assume experience with Linux and the command line.&lt;/p&gt;

&lt;p&gt;ACLs must be supported and enabled by the filesystem (mounted with the &lt;code&gt;acl&lt;/code&gt; option). As &lt;code&gt;systemd&lt;/code&gt; depends on the &lt;code&gt;acl&lt;/code&gt; package and the most common filesystems have ACLs enabled by default, any modern Linux distribution should work.&lt;/p&gt;

&lt;p&gt;If you are unsure if ACLs are enabled, you can check this with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tune2fs &lt;span class="nt"&gt;-l&lt;/span&gt; /dev/sdXY | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Default mount options:"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If enabled, the output should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Default mount options:    user_xattr acl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To set &lt;code&gt;acl&lt;/code&gt; as a default mount option for a filesystem, use the &lt;code&gt;tune2fs&lt;/code&gt; utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tune2fs &lt;span class="nt"&gt;-o&lt;/span&gt; acl /dev/sdXY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What exactly are ACLs
&lt;/h2&gt;

&lt;p&gt;Access Control Lists allow for more fine-grained and flexible permissions for files and directories. Based on the draft for POSIX 1003.1e, ACLs are a superset of standard Linux permissions.&lt;/p&gt;

&lt;p&gt;They are handy if you have complex permission requirements. For example, you got a docroot of your Web application owned by the &lt;code&gt;www-data&lt;/code&gt; user and the &lt;code&gt;developer&lt;/code&gt; group. The new product owner needs read access to the log files of the application. Now what? She does not have the same UID as the &lt;code&gt;www-data&lt;/code&gt; user, and adding her to the &lt;code&gt;developer&lt;/code&gt; group would be too permissive.&lt;/p&gt;

&lt;p&gt;This situation can be tricky as standard Linux permissions only allow one user and one group. Sure, you could make everything read-only to everyone, but that would be a bad idea. You can solve this situation with ACLs by adding a new user with read-only permissions to the docroot.&lt;/p&gt;

&lt;p&gt;The situation above is just a simple example, and there are way more complex scenarios that ACLs can solve.&lt;/p&gt;

&lt;p&gt;Even though the draft never made it to an official release, most Unix-like systems implemented Access Control Lists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap the Basics
&lt;/h2&gt;

&lt;p&gt;Before we dive in, let's quickly recap how basic permissions on Linux work. Linux gives us three entities for which we can manage permissions separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;U&lt;/strong&gt;ser (owner)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;G&lt;/strong&gt;roup (owner group)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O&lt;/strong&gt;ther (everyone else)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each entity, we can set three permissions (there are more, but for the sake of simplicity, we will ignore them for now):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;R&lt;/strong&gt;ead (octal 4)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;W&lt;/strong&gt;rite (octal 2)&lt;/li&gt;
&lt;li&gt;e &lt;strong&gt;X&lt;/strong&gt;ecute (octal 1)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drwxr-x--- 2 cassidy developer 4096 Sep 11 13:05 exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we can see that the owner is the user &lt;code&gt;cassidy&lt;/code&gt; and the owner group is &lt;code&gt;developer&lt;/code&gt;. Cassidy can read and create files in the directory, whereas the group members can only read/list the directory's content. Everyone else has no access at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Viewing current ACLs
&lt;/h2&gt;

&lt;p&gt;After we reviewed how basic permissions work, let's look at identifying files with Access Control Lists. Luckily &lt;code&gt;ls&lt;/code&gt; knows about ACLs and indicates what files have ACLs by appending a &lt;code&gt;+&lt;/code&gt; to the permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drwxr-x---+ 2 cassidy developer 4096 Sep 11 13:05 exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we know that this file has ACLs let's display all ACLs by using the &lt;code&gt;getfacl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[root@lab docroot]# getfacl exampledir
# file: exampledir
# owner: cassidy
# group: developer
user::rwx
user:finley:rwx            #effective:r-x
group::r-x
mask::r-x
other::---
default:user::rwx
default:user:finley:rwx    #effective:r-x
default:group::r-x
default:mask::r-x
default:other::---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a lot to digest. Let's break it down.&lt;/p&gt;

&lt;h2&gt;
  
  
  How ACLs work
&lt;/h2&gt;

&lt;p&gt;The first three lines display the filename, the owner, and the owner group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# file: exampledir
# owner: cassidy
# group: developer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next block specifies individual user permissions. This example shows that the user &lt;code&gt;finley&lt;/code&gt; has read and execution rights for this directory. The first line without a user name, &lt;code&gt;user::rwx&lt;/code&gt;, equals to the permission of the owner (Cassidy):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user::rwx
user:finley:rwx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The third block contains group permissions. In this case, there are only the permissions of the owner group, but there could be a named entry like &lt;code&gt;group:management:r-x&lt;/code&gt;, which would allow the &lt;code&gt;management&lt;/code&gt; group to access the contents of this directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;group::r-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we have the mask block. Masks can be challenging, and we will cover them later in detail. For now, keep in mind that masks limit access rights, and the comments like &lt;code&gt;#effective:r-x&lt;/code&gt; display the actual permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mask::r-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up is the &lt;code&gt;other&lt;/code&gt; block. It works like the previous blocks and specifies the permissions for everyone else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;other::---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we have the &lt;code&gt;default&lt;/code&gt; block. This block exists only on directories and includes all other blocks mentioned before. Here we can specify what permission should apply to new files within a directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default:user::rwx
default:user:finley:rwx    #effective:r-x
default:group::r-x
default:mask::r-x
default:other::---
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ACLs with only the three base entries &lt;code&gt;user::&lt;/code&gt;, &lt;code&gt;group::&lt;/code&gt; and &lt;code&gt;other::&lt;/code&gt; are called minimal ACLs. ACLs containing named entries are called extended ACLs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Masks and effective rights explained
&lt;/h3&gt;

&lt;p&gt;After looking at the output, let's address probably the most confusing aspect about Access Control Lists: Masks and effective rights.&lt;/p&gt;

&lt;p&gt;Standard permissions can't reflect complex ACLs. Therefore the working group agreed on a complex masking mechanism to preserve maximum compatibility between basic permissions and ACLs.&lt;/p&gt;

&lt;p&gt;To better understand masks, let's start with five simple statements that always will be true:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If the ACL has no mask entry, the permissions of the owner group will correspond to the ACL group.&lt;/li&gt;
&lt;li&gt;If the ACL has named users or groups, it will have a mask entry.&lt;/li&gt;
&lt;li&gt;If the ACL has a mask entry, the permissions of the owner group will correspond to the mask entry.&lt;/li&gt;
&lt;li&gt;Unless otherwise stated, the mask entry's permissions will be the union of all permissions affected by an ACL and recalculate on every change.&lt;/li&gt;
&lt;li&gt;Masks denote maximum access rights that can be granted by a named user entry, named group entry, or the &lt;code&gt;group::&lt;/code&gt; entry.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first statement is pretty self-explanatory. As long as there is no mask, the permissions of the owner group and the &lt;code&gt;group::&lt;/code&gt; entry will be the same. Changes to the owner group will be reflected in the &lt;code&gt;group::&lt;/code&gt; entry and the other way around.&lt;/p&gt;

&lt;p&gt;The next one states that as soon as you add named user or group entries, &lt;code&gt;setfacl&lt;/code&gt; will automatically add a mask entry if it does not exist.&lt;/p&gt;

&lt;p&gt;The third statement is where it gets interesting. If a mask exists, the meaning of the owner group will change. The owner group will equal the mask entry. Changes with &lt;code&gt;chmod&lt;/code&gt; to the owner group will change the mask entry. Changes via &lt;code&gt;setfacl&lt;/code&gt; to the mask entry will change the owner group's permissions.&lt;/p&gt;

&lt;p&gt;But how can we manage the permissions of the owner group without changing the mask? Don't worry. You can change permissions for the owner group via the &lt;code&gt;group::&lt;/code&gt; entry.&lt;/p&gt;

&lt;p&gt;Thanks to the fourth statement, we know that the mask's permissions can change and always equal the union of named users, named groups, and the &lt;code&gt;group::&lt;/code&gt; entry.&lt;/p&gt;

&lt;p&gt;To prevent the mask from recalculating on change, use &lt;code&gt;-n&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;The last statement lets us know, and this is important, that you can't grant more permissions than specified in the mask for named users, named groups, and &lt;code&gt;group::&lt;/code&gt; entries. This restriction is what causes the so-called effective rights.&lt;/p&gt;

&lt;p&gt;For example, if we add the following ACL and mask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user:finley:rwx
mask::r-x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user &lt;code&gt;finley&lt;/code&gt; only has the rights &lt;code&gt;rx&lt;/code&gt;, as &lt;code&gt;w&lt;/code&gt; is not allowed by the mask.&lt;/p&gt;

&lt;p&gt;Like every other entry, we can change the mask explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -m m:rw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unless you use &lt;code&gt;-n&lt;/code&gt; to prevent the mask from recalculating, all following changes will overwrite your mask again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Precedence of ACLs
&lt;/h3&gt;

&lt;p&gt;One last thing to understand is the following order in which the algorithm checks for permission:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;File owner.&lt;/li&gt;
&lt;li&gt;Named user entries.&lt;/li&gt;
&lt;li&gt;Owner group (or &lt;code&gt;group::&lt;/code&gt; entry).&lt;/li&gt;
&lt;li&gt;Named group entries&lt;/li&gt;
&lt;li&gt;Other&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first match determines the access to the resource. The order is essential, as it will deny writing access if a named user entry with &lt;code&gt;r&lt;/code&gt; exists even when the user is a member of matching group entry with correct permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[root@lab docroot]# getfacl exampledir
# file: exampledir
# owner: cassidy
# group: developer
user::rwx
user:finley:r-x
group::rwx
mask::rwx
other::r-x

[finley@lab docroot]$ groups
finley developer

[finley@lab docroot]$ touch exampledir/testfile
touch: cannot touch 'exampledir/testfile': Permission denied
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Working with ACL entries
&lt;/h2&gt;

&lt;p&gt;At this point, we should have a good understanding of how Access Control Lists work. Finally, let's modify ACLs. Fortunately, this is pretty straightforward. To set or remove ACLS, use the &lt;code&gt;setfacl&lt;/code&gt; command. The syntax is always:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl [option] [action/specification] file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A colon separates the specification into three sections: object type, associated object, and permissions. Here is a list of all object types:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Text form&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Owner&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_USER_OBJ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;u::rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Named user&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_USER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;u:name:rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner group&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_GROUP_OBJ&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;g::rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Named group&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_GROUP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;g:name:rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mask&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_MASK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;m::rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Others&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ACL_OTHER&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;o::rwx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The following example indicates that we want to modify the permissions for the user &lt;code&gt;finley&lt;/code&gt;. It is possible to use UIDs and specify permissions as octal numbers or characters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;u:finley:6
u:33:rw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can modify multiple entries simultaneously by separating specifications with a comma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;u:finley:rwx,g:accounting:rx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use &lt;code&gt;setfacl&lt;/code&gt; on a file system that does not support ACLs, &lt;code&gt;setfacl&lt;/code&gt; tries to reflect the desired permissions via the standard permissions and output an error. Be aware that this could lead to unexpected results.&lt;/p&gt;

&lt;p&gt;Here are some common options for &lt;code&gt;setfacl&lt;/code&gt;, but I will explain them in detail in the following sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you are unsure if your ACL results in the expected outcome, you can use the &lt;code&gt;--test&lt;/code&gt; option to display the new ACL entries without changing the current ones.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OPTION&lt;/th&gt;
&lt;th&gt;DESCRIPTION&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modify or add an ACL entry (always needs to be the last option).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets ACL entry as default (Only works on directories).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recursively applies changes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes specified entry.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes all default entries.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Removes all entries.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prevents the mask from being recalculated.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How to create/modify ACL entries
&lt;/h3&gt;

&lt;p&gt;To create or modify ACLs, use the modify option &lt;code&gt;-m&lt;/code&gt; and follow it with your specification explained above. If the same object exists, the new entry will overwrite existing permissions. For example, to add or change the permissions for the user &lt;code&gt;finley&lt;/code&gt; to &lt;code&gt;rwx&lt;/code&gt;, execute the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -m u:finely:rwx exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is crucial that after the option &lt;code&gt;-m&lt;/code&gt;, the specification follows immediately. So if you want to change the permissions recursively, you have to write &lt;code&gt;-Rm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-mR&lt;/code&gt; will result in an error!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If you want to apply read-only permissions for files and directories recursively, you can use &lt;code&gt;rX&lt;/code&gt;. A capital &lt;code&gt;X&lt;/code&gt; only applies execution rights to directories. So all files would get &lt;code&gt;r&lt;/code&gt; permissions, and all directories would become &lt;code&gt;rx&lt;/code&gt; permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating default permissions for new files
&lt;/h3&gt;

&lt;p&gt;If you want newly created files to get specific permissions automatically, you can specify default permissions on the parent directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -dm u:finely:rwx exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This only works for directories (&lt;code&gt;-Rdm&lt;/code&gt; ignores files). All new files and directories in &lt;code&gt;exampledir&lt;/code&gt; will inherit these permissions (new directories will also inherit the default entries). Unfortunately, this applies only to newly created files, not copied ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing ACL entries
&lt;/h3&gt;

&lt;p&gt;To remove single entries, use the &lt;code&gt;-x&lt;/code&gt; option instead of &lt;code&gt;-m&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -x g:accounting exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like with the &lt;code&gt;-m&lt;/code&gt; option, you can use the &lt;code&gt;-d&lt;/code&gt; switch to remove single default entries: &lt;code&gt;-dx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To remove all default entries, use the &lt;code&gt;-k&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -k exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to remove all ACL entries, you can nuke them with the &lt;code&gt;-b&lt;/code&gt; option, but be careful when to use it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setfacl -b exampledir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, be aware that unless you use the &lt;code&gt;-n&lt;/code&gt; switch, the mask will recalculate when removing entries. So check for possible breaking changes!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have now learned how Linux Access Control Lists work and how to use them. I hope it helps to solve complex permission structures more confidently.&lt;/p&gt;

&lt;p&gt;If you want to read more about ACLs, I recommend the article from Andreas Grünbacher, one of the draft's authors for POSIX ACLs. Not to mention the man pages for &lt;code&gt;acl&lt;/code&gt;, &lt;code&gt;getfacl&lt;/code&gt;, and &lt;code&gt;setfacl&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.usenix.org/legacy/publications/library/proceedings/usenix03/tech/freenix03/full_papers/gruenbacher/gruenbacher_html/main.html"&gt;POSIX Access Control Lists on Linux by Andreas Grünbacher&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linux.die.net/man/5/acl"&gt;acl - Linux man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linux.die.net/man/1/getfacl"&gt;getfacl - Linux man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linux.die.net/man/1/setfacl"&gt;setfacl - Linux man page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you found any mistakes or want to say hi, send me a message.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>tutorial</category>
      <category>linux</category>
      <category>firstpost</category>
    </item>
  </channel>
</rss>
