diff --git a/api/funkwhale_api/common/preferences.py b/api/funkwhale_api/common/preferences.py
index e6eb8bedaaa140a6fc496258d839a242e7e9e213..a2d3f04b7f2414aa1e9602330c65b1abe3a9a750 100644
--- a/api/funkwhale_api/common/preferences.py
+++ b/api/funkwhale_api/common/preferences.py
@@ -1,4 +1,8 @@
 from django.conf import settings
+from django import forms
+
+from dynamic_preferences import serializers
+from dynamic_preferences import types
 from dynamic_preferences.registries import global_preferences_registry
 
 
@@ -10,3 +14,38 @@ class DefaultFromSettingMixin(object):
 def get(pref):
     manager = global_preferences_registry.manager()
     return manager[pref]
+
+
+class StringListSerializer(serializers.BaseSerializer):
+    separator = ','
+    sort = True
+
+    @classmethod
+    def to_db(cls, value, **kwargs):
+        if not value:
+            return
+
+        if type(value) not in [list, tuple]:
+            raise cls.exception(
+                "Cannot serialize, value {} is not a list or a tuple".format(
+                    value))
+
+        if cls.sort:
+            value = sorted(value)
+        return cls.separator.join(value)
+
+    @classmethod
+    def to_python(cls, value, **kwargs):
+        if not value:
+            return []
+        return value.split(',')
+
+
+class StringListPreference(types.BasePreferenceType):
+    serializer = StringListSerializer
+    field_class = forms.MultipleChoiceField
+
+    def get_api_additional_data(self):
+        d = super(StringListPreference, self).get_api_additional_data()
+        d['choices'] = self.get('choices')
+        return d
diff --git a/api/funkwhale_api/users/dynamic_preferences_registry.py b/api/funkwhale_api/users/dynamic_preferences_registry.py
index 4f736053088df4fad3ccd804744c8dec826d388f..7108360b9a6d68be3afa827d804245a87bc3d8a4 100644
--- a/api/funkwhale_api/users/dynamic_preferences_registry.py
+++ b/api/funkwhale_api/users/dynamic_preferences_registry.py
@@ -1,6 +1,10 @@
 from dynamic_preferences import types
 from dynamic_preferences.registries import global_preferences_registry
 
+from funkwhale_api.common import preferences as common_preferences
+
+from . import models
+
 users = types.Section('users')
 
 
@@ -14,3 +18,23 @@ class RegistrationEnabled(types.BooleanPreference):
     help_text = (
         'When enabled, new users will be able to register on this instance.'
     )
+
+
+@global_preferences_registry.register
+class DefaultPermissions(common_preferences.StringListPreference):
+    show_in_api = True
+    section = users
+    name = 'default_permissions'
+    default = []
+    verbose_name = 'Default permissions'
+    help_text = (
+        'A list of default preferences to give to all registered users.'
+    )
+    choices = [
+        (k, c['label'])
+        for k, c in models.PERMISSIONS_CONFIGURATION.items()
+    ]
+    field_kwargs = {
+        'choices': choices,
+        'required': False,
+    }
diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py
index a739c1e384ef78f95f5a4b827e5f3d3c4227729c..a3c5bd0bfe3ea18d5133190b7105bc2e477a9b25 100644
--- a/api/funkwhale_api/users/models.py
+++ b/api/funkwhale_api/users/models.py
@@ -13,18 +13,33 @@ from django.utils.encoding import python_2_unicode_compatible
 from django.utils.translation import ugettext_lazy as _
 
 from funkwhale_api.common import fields
+from funkwhale_api.common import preferences
 
 
 def get_token():
     return binascii.b2a_hex(os.urandom(15)).decode('utf-8')
 
 
-PERMISSIONS = [
-    'federation',
-    'library',
-    'settings',
-    'upload',
-]
+PERMISSIONS_CONFIGURATION = {
+    'federation': {
+        'label': 'Manage library federation',
+        'help_text': 'Follow other instances, accept/deny library follow requests...',
+    },
+    'library': {
+        'label': 'Manage library',
+        'help_text': 'Manage library',
+    },
+    'settings': {
+        'label': 'Manage instance-level settings',
+        'help_text': '',
+    },
+    'upload': {
+        'label': 'Upload new content to the library',
+        'help_text': '',
+    },
+}
+
+PERMISSIONS = sorted(PERMISSIONS_CONFIGURATION.keys())
 
 
 @python_2_unicode_compatible
@@ -48,27 +63,34 @@ class User(AbstractUser):
 
     # permissions
     permission_federation = models.BooleanField(
-        'Manage library federation',
-        help_text='Follow other instances, accept/deny library follow requests...',
+        PERMISSIONS_CONFIGURATION['federation']['label'],
+        help_text=PERMISSIONS_CONFIGURATION['federation']['help_text'],
         default=False)
     permission_library = models.BooleanField(
-        'Manage library',
-        help_text='Manage library',
+        PERMISSIONS_CONFIGURATION['library']['label'],
+        help_text=PERMISSIONS_CONFIGURATION['library']['help_text'],
         default=False)
     permission_settings = models.BooleanField(
-        'Manage instance-level settings',
+        PERMISSIONS_CONFIGURATION['settings']['label'],
+        help_text=PERMISSIONS_CONFIGURATION['settings']['help_text'],
         default=False)
     permission_upload = models.BooleanField(
-        'Upload new content to the library',
+        PERMISSIONS_CONFIGURATION['upload']['label'],
+        help_text=PERMISSIONS_CONFIGURATION['upload']['help_text'],
         default=False)
 
     def __str__(self):
         return self.username
 
     def get_permissions(self):
+        defaults = preferences.get('users__default_permissions')
         perms = {}
         for p in PERMISSIONS:
-            v = self.is_superuser or getattr(self, 'permission_{}'.format(p))
+            v = (
+                self.is_superuser or
+                getattr(self, 'permission_{}'.format(p)) or
+                p in defaults
+            )
             perms[p] = v
         return perms
 
diff --git a/api/tests/common/test_preferences.py b/api/tests/common/test_preferences.py
new file mode 100644
index 0000000000000000000000000000000000000000..475610a937c6c007dca06dda7045e2d41b61f6d9
--- /dev/null
+++ b/api/tests/common/test_preferences.py
@@ -0,0 +1,44 @@
+import pytest
+
+from dynamic_preferences.registries import global_preferences_registry
+from funkwhale_api.common import preferences as common_preferences
+
+
+@pytest.fixture
+def string_list_pref(preferences):
+
+    @global_preferences_registry.register
+    class P(common_preferences.StringListPreference):
+        default = ['hello']
+        section = 'test'
+        name = 'string_list'
+    yield
+    del global_preferences_registry['test']['string_list']
+
+
+@pytest.mark.parametrize('input,output', [
+    (['a', 'b', 'c'], 'a,b,c'),
+    (['a', 'c', 'b'], 'a,b,c'),
+    (('a', 'c', 'b'), 'a,b,c'),
+    ([], None),
+])
+def test_string_list_serializer_to_db(input, output):
+    s = common_preferences.StringListSerializer.to_db(input) == output
+
+
+@pytest.mark.parametrize('input,output', [
+    ('a,b,c', ['a', 'b', 'c'], ),
+    (None, []),
+    ('', []),
+])
+def test_string_list_serializer_to_python(input, output):
+    s = common_preferences.StringListSerializer.to_python(input) == output
+
+
+def test_string_list_pref_default(string_list_pref, preferences):
+    assert preferences['test__string_list'] == ['hello']
+
+
+def test_string_list_pref_set(string_list_pref, preferences):
+    preferences['test__string_list'] = ['world', 'hello']
+    assert preferences['test__string_list'] == ['hello', 'world']
diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py
index 44574480242e10cd69c7afb05ad3d2621d738033..42123b5e866eac282bb8f20b14bdc96ec3d16fe7 100644
--- a/api/tests/users/test_models.py
+++ b/api/tests/users/test_models.py
@@ -41,6 +41,17 @@ def test_get_permissions_regular(factories):
             assert perms[p] is False
 
 
+def test_get_permissions_default(factories, preferences):
+    preferences['users__default_permissions'] = ['upload', 'federation']
+    user = factories['users.User']()
+
+    perms = user.get_permissions()
+    assert perms['upload'] is True
+    assert perms['federation'] is True
+    assert perms['library'] is False
+    assert perms['settings'] is False
+
+
 @pytest.mark.parametrize('args,perms,expected', [
     ({'is_superuser': True}, ['federation', 'library'], True),
     ({'is_superuser': False}, ['federation'], False),
diff --git a/changes/changelog.d/236.feature b/changes/changelog.d/236.feature
new file mode 100644
index 0000000000000000000000000000000000000000..379f9648ef441ba8e7196a221336188151e0caf9
--- /dev/null
+++ b/changes/changelog.d/236.feature
@@ -0,0 +1,2 @@
+Admins can now configure default permissions that will be granted to all
+registered users (#236)
diff --git a/front/src/components/admin/SettingsGroup.vue b/front/src/components/admin/SettingsGroup.vue
index 255f04488973fbc4eb5c1ecc5e97418294c258ff..f6d57c239b0d4d6bff7c6b0af1f6e397f2da941c 100644
--- a/front/src/components/admin/SettingsGroup.vue
+++ b/front/src/components/admin/SettingsGroup.vue
@@ -50,6 +50,13 @@
         <label :for="setting.identifier">{{ setting.verbose_name }}</label>
         <p v-if="setting.help_text">{{ setting.help_text }}</p>
       </div>
+      <select
+        v-else-if="setting.field.class === 'MultipleChoiceField'"
+        v-model="values[setting.identifier]"
+        multiple
+        class="ui search selection dropdown">
+        <option v-for="v in setting.additional_data.choices" :value="v[0]">{{ v[1] }}</option>
+      </select>
     </div>
     <button
       type="submit"
diff --git a/front/src/main.js b/front/src/main.js
index 2e92fbbd2243e20f567f47dcbcc5e5f3c7937659..eb2e3a23d6ceed3bdb88ed59d49df5a9744e4828 100644
--- a/front/src/main.js
+++ b/front/src/main.js
@@ -81,6 +81,8 @@ axios.interceptors.response.use(function (response) {
   }
   if (error.response.status === 404) {
     error.backendErrors.push('Resource not found')
+  } else if (error.response.status === 403) {
+    error.backendErrors.push('Permission denied')
   } else if (error.response.status === 500) {
     error.backendErrors.push('A server error occured')
   } else if (error.response.data) {
diff --git a/front/src/views/admin/Settings.vue b/front/src/views/admin/Settings.vue
index 81eb97aa6ec303b3a3c411a0022aa7a49c1ade30..10e32968d7dd46fd164002b020c46437d6391c14 100644
--- a/front/src/views/admin/Settings.vue
+++ b/front/src/views/admin/Settings.vue
@@ -51,12 +51,12 @@ export default {
         if (self.$store.state.route.hash) {
           self.scrollTo(self.$store.state.route.hash.substr(1))
         }
+        $('select.dropdown').dropdown()
       })
     })
   },
   methods: {
     scrollTo (id) {
-      console.log(id, 'hello')
       this.current = id
       document.getElementById(id).scrollIntoView()
     },
@@ -86,7 +86,8 @@ export default {
           id: 'users',
           settings: [
             'users__registration_enabled',
-            'common__api_authentication_required'
+            'common__api_authentication_required',
+            'users__default_permissions'
           ]
         },
         {