MariaDB'de bir hesaba yetki GRANT yetki ON seviye TO hesap; deyimiyle verilir, REVOKE yetki ON seviye FROM hesap; deyimiyle geri alınır. Örneğin bir web uygulamasının hesabına yalnızca kendi veritabanında okuma ve yazma izni vermek için GRANT SELECT, INSERT, UPDATE, DELETE ON uygulama.* TO 'app'@'localhost'; yazmanız yeterlidir. Hesabın o anda hangi yetkilere sahip olduğunu SHOW GRANTS FOR 'app'@'localhost'; ile görürsünüz.

Bu yazı yetki seviyelerini (genel, veritabanı, tablo, sütun, rutin), en sık kullanılan yetkileri, WITH GRANT OPTION, TO PUBLIC, yetki eşleşmesinin az bilinen kurallarını ve REVOKE ile ilgili tuzakları MariaDB Server belgelerine göre anlatıyor. Hesap açmayı CREATE USER yazısında, yetkileri gruplamayı rol yazısında bulabilirsiniz. Serinin geri kalanı için MariaDB öğrenme rehberi sayfasına göz atın.

GRANT deyiminin üç biçimi

Belgelere göre GRANT üç ana biçimde kullanılır: yetki vermek, bir hesaba başka bir hesap adına işlem yapma (PROXY) izni vermek ve bir rolü hesaba atamak. Bu yazının konusu birinci biçimdir; rol atama rol yazısında işleniyor. Yetki verme biçiminin iskeleti şöyledir:

sql
GRANT
    priv_type [(column_list)]
      [, priv_type [(column_list)]] ...
    ON [object_type] priv_level
    TO account_or_role [, account_or_role] ...
    [REQUIRE {NONE | tls_option [[AND] tls_option] ...}]
    [WITH grant_option_list]

GRANT kullanabilmek için GRANT OPTION yetkisine ve vermek istediğiniz yetkilerin kendisine sahip olmanız gerekir. Kendinizde olmayan bir yetkiyi başkasına veremezsiniz. Aynı deyimde virgülle birden fazla yetki ve birden fazla hesap yazılabilir. REQUIRE kısmı hesabın TLS ile bağlanmasını zorunlu kılmak içindir ve TLS yazısında anlatılıyor; WITH kısmına ise GRANT OPTION ya da kaynak sınırları yazılır.

Yetki seviyeleri

Yetki seviyeleri: Genel (global), Veritabanı, Tablo, Sütun

Yetkiler farklı kapsamlarda verilebilir ve her kapsam ayrı bir sistem tablosunda saklanır. Bazı yetkiler yalnızca belirli seviyelerde anlamlıdır; örneğin SHUTDOWN ya da PROCESS yalnızca genel seviyede verilir.

SeviyeON yazımıSaklandığı tablo
Genel (global)*.*mysql.global_priv
Veritabanıdb_adi.* (ya da geçerli veritabanı için *)mysql.db
Tablodb_adi.tablo_adi (ya da tablo_adi)mysql.tables_priv
SütunTablo seviyesi + yetkiden sonra sütun listesimysql.columns_priv
FonksiyonFUNCTION db_adi.rutin_adimysql.procs_priv
ProsedürPROCEDURE db_adi.rutin_adimysql.procs_priv

Veritabanı seviyesinde verilen tablo ve fonksiyon yetkileri, o veritabanında daha sonra oluşturulacak nesneleri de kapsar. Genel seviyede verilen yetkiler de aynı şekilde sonradan açılacak tüm veritabanlarına uygulanır. Belgelerin vurguladığı bir ayrıntı: genel yetkiler hemen etkili olmaz, yalnızca GRANT çalıştıktan sonra açılan bağlantılara uygulanır. Bir kullanıcıya genel yetki verdiyseniz yeniden bağlanmasını isteyin.

En sık kullanılan yetkiler

Yetki listesi uzundur; günlük işlerde çoğunlukla aşağıdakiler kullanılır. Tam liste ve her yetkinin açıklaması resmî GRANT sayfasında yer alıyor.

YetkiSeviyeNe sağlar
SELECTTablo / sütunSatırları okumak
INSERTTablo / sütunSatır eklemek
UPDATETablo / sütunSatır güncellemek; WHERE için SELECT de gerekir
DELETETabloSatır silmek
CREATEVeritabanı / tabloVeritabanı ya da tablo oluşturmak
DROPVeritabanı / tabloSilmek; TRUNCATE TABLE için de gerekir
ALTERTabloTablo yapısını değiştirmek
INDEXTabloCREATE INDEX ile index eklemek
CREATE VIEW / SHOW VIEWTabloView oluşturmak / tanımını görmek
TRIGGERTabloTrigger oluşturmak, silmek, tanımını görmek
EXECUTEFonksiyon / prosedürSaklı rutini çalıştırmak
CREATE ROUTINE / ALTER ROUTINEVeritabanı / rutinSaklı rutin oluşturmak / değiştirmek
EVENTVeritabanıZamanlanmış olay oluşturmak ve değiştirmek
LOCK TABLESVeritabanıLOCK TABLES; ayrıca SELECT gerekir
FILEGenelLOAD DATA INFILE, LOAD_FILE() ile sunucu dosyalarını okumak / yazmak
PROCESSGenelTüm iş parçacıklarını SHOW PROCESSLIST ile görmek
RELOADGenelFLUSH deyimlerini çalıştırmak
SHUTDOWNGenelSunucuyu kapatmak

Belgelerdeki birkaç ayrıntı sık karıştırılır. INDEX yetkisi olmadan da CREATE TABLE içinde index tanımlanabilir (CREATE yetkiniz varsa) ya da ALTER TABLE ile index eklenebilir (ALTER yetkiniz varsa). REFERENCES yetkisi listede bulunur ama belgelerde kullanılmadığı belirtilir. FILE yetkisi sunucunun dosya sistemine erişim açtığı için uygulama hesaplarına verilmemelidir; dosya içe aktarma LOAD DATA yazısında ele alınıyor.

SUPER yetkisinin bölünmesi

Eskiden birçok yönetim işi tek bir SUPER yetkisine bağlıydı. Belgelere göre bu yetki daha ince parçalara ayrılmıştır: SET USER, FEDERATED ADMIN, CONNECTION ADMIN, REPLICATION SLAVE ADMIN, BINLOG ADMIN, BINLOG REPLAY, REPLICA MONITOR, BINLOG MONITOR, REPLICATION MASTER ADMIN ve READ_ONLY ADMIN. MariaDB 11.0'dan itibaren bunlar artık SUPER'ın parçası değildir ve ayrı ayrı verilmeleri gerekir. Örneğin read_only açıkken yazabilmek için READ_ONLY ADMIN gerekir; bu yetkiyi kimseye vermeyerek bir replikada hiç kimsenin geçici olmayan tabloları değiştirememesini sağlayabilirsiniz. Replikasyon hesapları için gereken REPLICATION SLAVE yetkisi replikasyon yazısında kullanılıyor.

USAGE, ALL PRIVILEGES ve GRANT OPTION

USAGE, ALL PRIVILEGES ve GRANT OPTION

USAGE gerçekte hiçbir yetki vermez. Yeni açılmış bir hesabın SHOW GRANTS çıktısında genel USAGE görünmesinin nedeni budur. GRANT USAGE ile hesabın yetkilerini değiştirmeden yalnızca MAX_USER_CONNECTIONS gibi seçenekleri ayarlayabilirsiniz.

ALL PRIVILEGES (kısaca ALL) yalnızca yazdığınız seviyedeki tüm yetkileri verir. Bir tabloya ALL vermek veritabanı ya da genel seviyede bir şey vermez. Ayrıca ALL PRIVILEGES özel GRANT OPTION yetkisini kapsamaz.

WITH GRANT OPTION, hesabın o seviyede sahip olduğu yetkileri başkalarına verebilmesini sağlar. Sütun seviyesinde verilemez; sütun yetkisiyle birlikte yazılırsa tüm tablo için verilir. Belgelerde root benzeri bir yönetici hesabı şöyle oluşturulur:

sql
CREATE USER 'alexander'@'localhost';
GRANT ALL PRIVILEGES ON  *.* TO 'alexander'@'localhost' WITH GRANT OPTION;

Uygulamaya göre yetki vermek: küçük bir örnek

Tipik bir senaryo düşünelim: magaza veritabanını kullanan bir web uygulaması, rapor almak için ayrı bir okuma hesabı ve şema değişikliklerini yapan bir bakım hesabı. Aşağıdaki deyimler belgelerdeki sözdizimine göre yazıldı; hesap adları örnek amaçlıdır.

sql
CREATE USER 'magaza_app'@'localhost' IDENTIFIED BY 'guclu-bir-parola';
GRANT SELECT, INSERT, UPDATE, DELETE ON magaza.* TO 'magaza_app'@'localhost';

CREATE USER 'rapor'@'10.0.0.%' IDENTIFIED BY 'baska-bir-parola';
GRANT SELECT ON magaza.* TO 'rapor'@'10.0.0.%';

CREATE USER 'bakim'@'localhost' IDENTIFIED BY 'ucuncu-parola';
GRANT ALL PRIVILEGES ON magaza.* TO 'bakim'@'localhost';

Uygulama hesabı tablo oluşturamaz ya da silemez; bir SQL injection açığı olsa bile saldırganın yapabilecekleri bu hesabın yetkileriyle sınırlı kalır. Bakım hesabının ALL yetkisi ise yalnızca magaza veritabanını kapsar, diğer veritabanlarına ya da genel yönetim işlerine uzanmaz.

Sütun ve rutin yetkileri

Hassas sütunları gizlemek için sütun seviyesinde yetki verebilirsiniz. Belgelerdeki örnek, kullanıcının çalışanların adını ve pozisyonunu görmesine izin verir ama maaş gibi diğer sütunlara erişimini kapatır. Sütun seviyesinde SELECT yetkisi olmayan sütunlar WHERE, ON, GROUP BY ve ORDER BY içinde de kullanılamaz.

sql
GRANT SELECT (name, position) ON Employee TO 'jeffrey'@'localhost';

Saklı prosedür çalıştırma izni EXECUTE ile verilir. Belgeler, bir prosedürü çağırma yetkisinin normalde yapamayacağınız işlemlere (örneğin bir tabloya satır eklemeye) kapı açabileceğini hatırlatır. Saklı rutinlerin güvenlik bağlamı stored procedure yazısında anlatılıyor.

sql
GRANT EXECUTE ON PROCEDURE mysql.create_db TO maintainer;

GRANT ile örtük hesap oluşturma

GRANT, hesap yoksa onu örtük olarak da oluşturabilir; bunun için CREATE USER için gereken yetkilere sahip olmanız gerekir. Ancak sql_mode içinde NO_AUTO_CREATE_USER açıksa (belgelere göre varsayılan budur) kimlik doğrulama bilgisi verilmeden yeni hesap oluşturulamaz. Belgelerdeki örnekte boş parolayla denenen GRANT hata verir:

sql
GRANT USAGE ON *.* TO 'user123'@'%' IDENTIFIED BY '';
text
ERROR 1133 (28000): Can't find any matching row in the user table

Bu davranış yazım hatalarına karşı da bir korumadır: hesap adını yanlış yazdığınızda yanlışlıkla yeni ve parolasız bir hesap açılmaz. Önerilen yol hesabı önce CREATE USER ile açmak, sonra yetki vermektir.

Yetki eşleşmesinin az bilinen kuralı

Bağlantı sırasında MariaDB tek bir hesap seçer: kullanıcı adı birebir eşleşen ve host deseni en özgül olan hesap. Bu hesap kimliğinizi ve CURRENT_USER() değerini belirler; genel yetkileriniz de yalnızca bu hesabın mysql.global_priv satırından gelir. Veritabanı, tablo, sütun ve rutin yetkileri ise ayrı ayrı aranır: her seviyede, bağlanan hesabın kullanıcı adı ve istemcinin gerçekten bağlandığı host ile en özgül kayıt bulunur ve tek başına uygulanır. Daha genel host desenine ait kayıtlar buna eklenmez.

Belgelerdeki örnekte foo@localhost ve foo@'%' diye iki hesap var ve db veritabanında SELECT yalnızca foo@'%' hesabına verilmiş:

sql
CREATE USER foo@localhost;
CREATE USER foo@'%';
CREATE DATABASE db;
CREATE TABLE db.t1 (a INT);
INSERT INTO db.t1 VALUES (1),(2),(3);
GRANT SELECT ON db.* TO foo@'%';

Yerelden bağlanan foo, foo@localhost olarak doğrulanır; ama foo@localhost hesabının veritabanı seviyesinde hiç kaydı olmadığı için foo@'%' kaydı eşleşir ve SELECT başarılı olur. Şimdi foo@localhost hesabına aynı veritabanında herhangi bir yetki verelim:

sql
GRANT INSERT ON db.* TO foo@localhost;
SELECT * FROM db.t1;
text
ERROR 1142 (42000): SELECT command denied to user 'foo'@'localhost' for table `db`.`t1`

Artık daha özgül bir kayıt olduğu için o kayıt tek başına geçerlidir ve SELECT reddedilir. Belgeler ayrıca SHOW GRANTS çıktısının yalnızca doğrulanan hesaba kayıtlı yetkileri gösterdiğini, başka bir hesabın kaydından gelen yetkileri listelemediğini belirtir. Yani SHOW GRANTS bazen bağlantının gerçekte sahip olduğundan daha az yetki gösterebilir.

Veritabanı adında joker karakter

GRANT içinde veritabanı adında % ve _ kullanılabilir. Birden çok desen eşleşirse daha az veritabanıyla eşleşebilen, yani daha özgül desen uygulanır ve yalnızca ilk eşleşen kayıt geçerli olur. Belgelerdeki örnekte `%test`.* deseni `j-%`.* deseninden daha özgül sayılır; bu yüzden j-test veritabanında yalnızca SELECT geçerli olur, INSERT verilmez.

sql
CREATE USER 'jtest'@localhost IDENTIFIED BY 'jtest';
GRANT SELECT ON `%test`.* TO 'jtest'@localhost;
GRANT SELECT, INSERT, DELETE ON `j-%`.* TO 'jtest'@localhost;

TO PUBLIC: herkese birden yetki

MariaDB 10.11'den itibaren GRANT ... TO PUBLIC ile sunucuya erişimi olan tüm kullanıcılara, sonradan oluşturulacaklar da dahil, yetki verilebilir. Kullanıcı SHOW GRANTS çalıştırdığında PUBLIC'ten gelen yetkileri de görür; yalnızca PUBLIC yetkilerini görmek için SHOW GRANTS FOR PUBLIC kullanılır. Belgelerdeki çıktı şöyledir:

sql
GRANT ALL ON dev_db.* TO PUBLIC;

SHOW GRANTS FOR PUBLIC;
+------------------------------------------------+
| Grants for PUBLIC                              |
+------------------------------------------------+
| GRANT ALL PRIVILEGES ON `dev_db`.* TO `PUBLIC` |
+------------------------------------------------+

SHOW GRANTS ile yetkileri görmek

SHOW GRANTS FOR hesap, o hesabın yetkilerini yeniden oluşturmak için gereken GRANT deyimlerini listeler. Yalnızca kullanıcı adını yazarsanız host '%' kabul edilir. Kendi yetkilerinizi görmek için SHOW GRANTS, SHOW GRANTS FOR CURRENT_USER ya da SHOW GRANTS FOR CURRENT_USER() yazabilirsiniz. Belgelerdeki root çıktısı şöyledir:

sql
SHOW GRANTS FOR 'root'@'localhost';
+---------------------------------------------------------------------+
| Grants for root@localhost                                           |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION |
+---------------------------------------------------------------------+

Bu deyim SQL SECURITY DEFINER ile tanımlanmış bir saklı prosedür içinde çalışırsa çağıranın değil, tanımlayanın yetkilerini gösterir. Hesabın parolası, kilidi ve kaynak sınırları gibi yetki dışı bilgileri ise SHOW CREATE USER gösterir.

REVOKE ile yetkiyi geri almak

REVOKE, GRANT ile aynı seviye ve yetki adlarını kullanır. İlk biçim belirli bir seviyedeki yetkiyi alır ve ON yan cümlesi zorunludur:

sql
REVOKE SUPER ON *.* FROM 'myuser'@'localhost';
REVOKE ALL ON *.* FROM 'myuser'@'localhost';

Burada sık yapılan bir yanılgı var: REVOKE ALL ON *.* yalnızca genel seviyedeki yetkileri alır; veritabanı ya da tablo seviyesinde verilmiş yetkiler kalabilir. Tüm seviyelerdeki yetkileri ve GRANT OPTION'ı bir seferde almak için ikinci biçim tercih edilir. Bu biçimde ON *.* yazılmaz; yazılırsa hata verir:

sql
REVOKE ALL, GRANT OPTION FROM 'myuser'@'localhost';

Her iki durumda da hesap USAGE yetkisini korur, yani sunucuya bağlanmaya devam edebilir. Hesabın bağlanmasını da engellemek istiyorsanız DROP USER ile silmeniz ya da ACCOUNT LOCK ile kilitlemeniz gerekir.

Sık yapılan hatalar

Sık yapılan hatalar: Genel yetkinin hemen etkili olmasını beklemek, Uygulama hesabına *.* üzerinde ALL vermek, ALL PRIVILEGES'ın GRANT OPTION'ı kapsadığını sanmak, REVOKE ALL ON...
  • Genel yetkinin hemen etkili olmasını beklemek: Genel yetkiler yalnızca yeni bağlantılara uygulanır.
  • Uygulama hesabına *.* üzerinde ALL vermek: Uygulamanın ihtiyacı genellikle tek bir veritabanındaki SELECT, INSERT, UPDATE, DELETE yetkileridir.
  • ALL PRIVILEGES'ın GRANT OPTION'ı kapsadığını sanmak: Kapsamaz; gerekiyorsa WITH GRANT OPTION ayrıca yazılır.
  • REVOKE ALL ON *.* ile her şeyin alındığını sanmak: Alt seviyedeki yetkiler kalabilir; REVOKE ALL, GRANT OPTION FROM ... kullanın.
  • Yetkiyi yanlış host kısmına vermek: 'app'@'%' hesabına verilen yetki, 'app'@'localhost' olarak doğrulanan bağlantıda o seviyede daha özgül bir kayıt varsa uygulanmaz.
  • Rol ve kullanıcıya aynı adı vermek: Belgelere göre çakışmada rol adı önceliklidir ve GRANT yetkiyi kullanıcıya değil role verir.
  • FLUSH PRIVILEGES'ı gereksiz yere çalıştırmak: GRANT ve REVOKE sonrasında gerekmez; yalnızca mysql tablolarını elle değiştirdiğinizde gerekir.

Sık Sorulan Sorular

Bir kullanıcıya yalnızca tek bir veritabanında tam yetki nasıl verilir?

GRANT ALL PRIVILEGES ON veritabani.* TO 'kullanici'@'host'; yeterlidir. Bu yetki diğer veritabanlarını ve sunucu yönetimi yetkilerini kapsamaz; o veritabanında sonradan açılacak tabloları ise kapsar.

Yetkiyi verdim ama kullanıcı hâlâ erişemiyor, neden?

Önce yetkinin doğru hesaba (doğru host kısmıyla) verildiğini kontrol edin; bağlantıda SELECT CURRENT_USER(); hangi hesap olarak doğrulandığınızı gösterir. Genel yetkiyse kullanıcının yeniden bağlanması gerekir. Erişim hataları için sık hatalar yazısına bakabilirsiniz.

Aynı yetkileri birçok kullanıcıya vermenin kolay yolu var mı?

Evet, roller. Yetkileri bir role verip rolü kullanıcılara atarsınız; değişiklik tek yerden yapılır. Ayrıntılar MariaDB rolleri yazısında.

REVOKE sonrası kullanıcı neden hâlâ bağlanabiliyor?

Çünkü REVOKE hesabı silmez; hesap USAGE ile bağlanmaya devam eder. Bağlantıyı engellemek için hesabı silin ya da kilitleyin.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: MariaDB öğrenme rehberi · MariaDB CREATE USER · MariaDB rolleri · MariaDB TLS bağlantı · MariaDB replikasyon · SQL injection önleme · PHP PDO veritabanı bağlantısı